diff --git a/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java b/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java
index 585621dd5fd6b361111070aef3cfa135defec7de..b100cb2178d8d9ffcd16e382d79feea7f10dc017 100644
--- a/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java
+++ b/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java
@@ -20,89 +20,171 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
- * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java,v 1.1 2006-05-31 09:49:07 tjc Exp $
+ * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java,v 1.2 2006-07-04 15:57:57 tjc Exp $
  */
 
 package uk.ac.sanger.artemis.components.genebuilder;
 
 import javax.swing.*;
+
 import java.awt.*;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import uk.ac.sanger.artemis.Entry;
+import uk.ac.sanger.artemis.EntryChangeEvent;
+import uk.ac.sanger.artemis.EntryChangeListener;
+import uk.ac.sanger.artemis.EntryGroup;
 import uk.ac.sanger.artemis.Feature;
-import uk.ac.sanger.artemis.components.QualifierTextArea;
-import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
-import uk.ac.sanger.artemis.io.EntryInformation;
+import uk.ac.sanger.artemis.FeatureChangeEvent;
+import uk.ac.sanger.artemis.FeatureChangeListener;
+import uk.ac.sanger.artemis.GotoEventSource;
+import uk.ac.sanger.artemis.Selection;
+import uk.ac.sanger.artemis.components.FeatureEdit;
 import uk.ac.sanger.artemis.io.GFFStreamFeature;
-import uk.ac.sanger.artemis.io.Qualifier;
-import uk.ac.sanger.artemis.io.QualifierInfo;
-import uk.ac.sanger.artemis.io.QualifierVector;
-import uk.ac.sanger.artemis.io.StreamQualifier;
-import uk.ac.sanger.artemis.util.StringVector;
+
 
 public class GeneBuilderFrame extends JFrame
+       implements EntryChangeListener, FeatureChangeListener
 {
   
-  public GeneBuilderFrame(final Feature gene_feature)
+  private Feature active_feature; 
+  private FeatureEdit feature_editor;
+  
+  public GeneBuilderFrame(final Feature feature,
+                          final EntryGroup entry_group,
+                          final Selection selection,
+                          final GotoEventSource goto_event_source)
   {
-    super("Artemis Gene Builder: " + gene_feature.getIDString() +
-          (gene_feature.isReadOnly() ?
+    super("Artemis Gene Builder: " + feature.getIDString() +
+          (feature.isReadOnly() ?
           "  -  (read only)" :
           ""));
     
-    QualifierTextArea qualifier_text_area = new QualifierTextArea();
-    GFFStreamFeature gff_feature = (GFFStreamFeature)gene_feature.getEmblFeature();
+    this.active_feature = feature;
+
+    GFFStreamFeature gff_feature = (GFFStreamFeature)feature.getEmblFeature();
     GeneComponentTree tree = new GeneComponentTree(gff_feature.getChadoGene(),
-                                                   qualifier_text_area);
-    getContentPane().add(new JScrollPane(tree), BorderLayout.WEST);
+                                                   this);
+    
+    JScrollPane jsp_tree = new JScrollPane(tree);
+    jsp_tree.setPreferredSize( new Dimension(150, jsp_tree.getPreferredSize().height) );
+    getContentPane().add(jsp_tree, BorderLayout.WEST);
     
     GeneViewerPanel viewer = new GeneViewerPanel(gff_feature.getChadoGene());
     getContentPane().add(viewer, BorderLayout.CENTER);
 
-    qualifier_text_area.setWrapStyleWord(true);
-    qualifier_text_area.setText(getQualifierString(gene_feature));
+    if(entry_group != null)
+    {
+      JTabbedPane tabpane = new JTabbedPane();
     
-    getContentPane().add(new JScrollPane(qualifier_text_area), BorderLayout.SOUTH);
+      feature_editor = new FeatureEdit(feature, entry_group,
+                                       selection, goto_event_source, this);
+      tabpane.addTab("Annotation", feature_editor);
+
+      getContentPane().add(tabpane, BorderLayout.SOUTH);
+    }
+    
+    addWindowListener(new WindowAdapter() 
+    {
+      public void windowClosing(WindowEvent event) 
+      {
+        stopListening();
+        dispose();
+      }
+    });
     
     pack();
     setVisible(true);
   }
+  
+  protected void setActiveFeature(final Feature active_feature)
+  {
+    if(this.active_feature != null)
+      stopListening();
+    
+    this.active_feature = active_feature;
+    feature_editor.setActiveFeature(active_feature);
+  }
 
   /**
-   *  Return a string containing one qualifier per line.  These are the
-   *  original qualifiers, not the qualifiers from the qualifier_text_area.
+   *  Remove this object as a feature and entry change listener.
    **/
-  protected static String getQualifierString(final Feature feature) 
+  private void stopListening() 
   {
-    final StringBuffer buffer = new StringBuffer();
-    final QualifierVector qualifiers = feature.getQualifiers();
+    getEntry().removeEntryChangeListener(this);
+    active_feature.removeFeatureChangeListener(this);
+  }
 
-    for(int qualifier_index = 0; qualifier_index < qualifiers.size();
-        ++qualifier_index) 
+  /**
+   *  Implementation of the EntryChangeListener interface.  We listen to
+   *  EntryChange events so we can notify the user if of this component if the
+   *  feature gets deleted.
+   **/
+  public void entryChanged(EntryChangeEvent event) 
+  {
+    switch(event.getType())
     {
-      final Qualifier this_qualifier = (Qualifier)qualifiers.elementAt(qualifier_index);
-
-      final QualifierInfo qualifier_info =
-                       getEntryInformation(feature).getQualifierInfo(this_qualifier.getName());
-
-      final StringVector qualifier_strings =
-                       StreamQualifier.toStringVector(qualifier_info, this_qualifier);
-
-      for(int value_index = 0; value_index < qualifier_strings.size();
-          ++value_index)
-      {
-        final String qualifier_string = (String)qualifier_strings.elementAt(value_index);
-        buffer.append(qualifier_string + "\n");
-      }
+      case EntryChangeEvent.FEATURE_DELETED:
+        if(event.getFeature() == active_feature) 
+        {
+          stopListening();
+          dispose();
+        }
+        break;
+      default:
+        // do nothing;
+        break;
     }
-
-    return buffer.toString();
   }
   
   /**
-   *  Return the EntryInformation object of the entry containing the feature.
+   *  Implementation of the FeatureChangeListener interface.  We need to
+   *  listen to feature change events from the Features in this object so that
+   *  we can update the display.
+   *  @param event The change event.
    **/
-  protected static EntryInformation getEntryInformation(final Feature feature) 
+  public void featureChanged(FeatureChangeEvent event) 
   {
-    return feature.getEntry().getEntryInformation();
-  }
+    active_feature.resetColour();
+    /*
+    // re-read the information from the feature
+    switch(event.getType()) 
+    {
+      case FeatureChangeEvent.LOCATION_CHANGED:
+        updateLocation();
+        break;
+      case FeatureChangeEvent.KEY_CHANGED:
+        updateKey();
+        break;
+      case FeatureChangeEvent.QUALIFIER_CHANGED:
+        if(qualifier_text_area.getText().equals(orig_qualifier_text)) 
+          updateFromFeature();
+        else
+        {
+          final String message =
+            "warning: the qualifiers have changed outside the editor - " +
+            "view now?";
 
+          final YesNoDialog yes_no_dialog =
+            new YesNoDialog(FeatureEdit.this, message);
+
+          if(yes_no_dialog.getResult()) 
+            new FeatureViewer(gene_feature);
+        }
+        break;
+      default:
+        updateFromFeature();
+        break;
+    }
+    */
+  }
+  
+  
+  private Entry getEntry()
+  {
+    return active_feature.getEntry();
+  }
+  
+  
 }
\ No newline at end of file
diff --git a/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java b/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java
index 0395a0edeaf1f8acb155ce2e616a49e0d2f07f40..70ff8b0b72e691bd8feb67390d0bdf606b12f2cc 100644
--- a/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java
+++ b/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java
@@ -20,21 +20,21 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
- * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java,v 1.2 2006-05-31 15:40:53 tjc Exp $
+ * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java,v 1.3 2006-07-04 15:57:57 tjc Exp $
  */
 
 package uk.ac.sanger.artemis.components.genebuilder;
 
-import uk.ac.sanger.artemis.components.QualifierTextArea;
 import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
 import uk.ac.sanger.artemis.io.Feature;
 import uk.ac.sanger.artemis.io.InvalidRelationException;
+import uk.ac.sanger.artemis.chado.ChadoFeature;
 
 import javax.swing.*;
 import javax.swing.event.*;
 
 import javax.swing.tree.*;
-import java.util.Vector;
+import java.util.List;
 
 /**
  * Tree to display a gene hierarchy.
@@ -43,9 +43,9 @@ public class GeneComponentTree extends JTree
 {
   
   public GeneComponentTree(final ChadoCanonicalGene chado_gene,
-                           final QualifierTextArea qualifier_text_area)
+                           final GeneBuilderFrame gene_builder)
   {
-    final Feature gene = chado_gene.getGene();
+    final Feature gene = (Feature)chado_gene.getGene();
     final String gene_id;
     try
     {
@@ -72,9 +72,8 @@ public class GeneComponentTree extends JTree
         if(node == null)
           return;
        
-        Feature feature = chado_gene.getFeatureFromId((String)node.getUserObject());
-        qualifier_text_area.setText( GeneBuilderFrame.getQualifierString(
-             (uk.ac.sanger.artemis.Feature)feature.getUserData() ) );
+        Feature feature = (Feature)chado_gene.getFeatureFromId((String)node.getUserObject());
+        gene_builder.setActiveFeature((uk.ac.sanger.artemis.Feature)feature.getUserData());
       }
     });
     
@@ -91,8 +90,8 @@ public class GeneComponentTree extends JTree
                            final ChadoCanonicalGene chado_gene) 
           throws InvalidRelationException 
   {
-    Vector transcripts = chado_gene.getTranscripts();
-    Vector exons;
+    List transcripts = chado_gene.getTranscripts();
+    List exons;
     Feature transcript;
     Feature exon;
     Feature protein;
@@ -116,13 +115,19 @@ public class GeneComponentTree extends JTree
 
       for(int j=0; j<exons.size(); j++)
       {
-        exon = (Feature)exons.get(j);
-        exon_id = (String)exon.getQualifierByName("ID").getValues().get(0);
+        if(exons.get(j) instanceof Feature)
+        {
+          exon = (Feature)exons.get(j);
+          exon_id = (String)exon.getQualifierByName("ID").getValues().get(0);
+        }
+        else  // ChadoFeature
+          exon_id = ((ChadoFeature)exons.get(j)).getUniquename();
+        
         exon_node = new DefaultMutableTreeNode(exon_id);
         transcript_node.add(exon_node);
       }
       
-      protein = chado_gene.getProteinOfTranscript(transcript_id);
+      protein = (Feature)chado_gene.getProteinOfTranscript(transcript_id);
       if(protein == null)
         continue;
       
diff --git a/uk/ac/sanger/artemis/components/genebuilder/GeneEdit.java b/uk/ac/sanger/artemis/components/genebuilder/GeneEdit.java
new file mode 100644
index 0000000000000000000000000000000000000000..9967cbd9ddaa3971c442b9248def3e5cf04824a1
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/genebuilder/GeneEdit.java
@@ -0,0 +1,434 @@
+/* 
+ *
+ * created: 2006
+ *
+ * This file is part of Artemis
+ *
+ * Copyright (C) 2006  Genome Research Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+package uk.ac.sanger.artemis.components.genebuilder;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+
+import java.sql.SQLException;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+
+import javax.swing.JComboBox;
+import javax.swing.JScrollPane;
+import javax.swing.JPanel;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.Box;
+
+import uk.ac.sanger.artemis.chado.*;
+import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
+import uk.ac.sanger.artemis.io.InvalidRelationException;
+import uk.ac.sanger.artemis.io.GFFStreamFeature;
+import uk.ac.sanger.artemis.io.ReadFormatException;
+import uk.ac.sanger.artemis.util.DatabaseDocument;
+import uk.ac.sanger.artemis.util.ByteBuffer;
+
+
+/**
+ * Chado data access example code. This searches for features by their
+ * uniquename and returns their properties and attributes.
+ * 
+ * @author tjc
+ * 
+ */
+public class GeneEdit
+{
+  /** JDBC DAO */
+  private JdbcDAO jdbcDAO = null;
+
+  /** iBatis DAO */
+  private IBatisDAO connIB = null;
+
+  /** database URL */
+  private String location;
+
+  /** password fields */
+  private JPasswordField pfield;
+
+  /** <code>List</code> of <code>ChadoFeature</code> objects */
+  private List featureList;
+
+  /**
+   * 
+   * 
+   */
+  public GeneEdit()
+  {
+    try
+    {
+      setLocation();
+      final ChadoDAO dao = getDAO();
+      showFeatureSearchPanel(dao);
+    }
+    catch(java.net.ConnectException ce)
+    {
+      ce.printStackTrace();
+    }
+    catch(SQLException sqlExp)
+    {
+      JOptionPane.showMessageDialog(null, "SQL Problems...\n"
+          + sqlExp.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE);
+      sqlExp.printStackTrace();
+    }
+
+  }
+
+  /**
+   * Display a window for searching for features.
+   * 
+   * @throws java.net.ConnectException
+   * @throws SQLException
+   */
+  private void showFeatureSearchPanel(final ChadoDAO dao)
+      throws java.net.ConnectException, SQLException
+  {
+    int index = location.indexOf('=') + 1;
+    String schema = location.substring(index);
+
+    final List schemas = dao.getSchema();
+
+    Vector v_schemas = new Vector(schemas);
+    v_schemas.add(0, "All");
+
+    final JPanel panel = new JPanel(new BorderLayout());
+    final JComboBox schema_list = new JComboBox(v_schemas);
+    schema_list.setSelectedItem(schema);
+    
+
+    JScrollPane jsp = new JScrollPane(schema_list);
+    panel.add(jsp, BorderLayout.EAST);
+
+    Box xbox = Box.createHorizontalBox();
+    final JTextField gene_text = new JTextField(20);
+    gene_text.setText("AfA24A6.005"); //"SPAC212.04c");
+    xbox.add(gene_text);
+    gene_text.selectAll();
+    
+    
+    JButton findButt = new JButton("RETRIEVE");
+    findButt.addActionListener(new ActionListener()
+    {
+
+      public void actionPerformed(ActionEvent event)
+      {
+        String search_gene = gene_text.getText();
+        String schema = (String)schema_list.getSelectedItem();
+        List schema_search;
+        if(schema.equalsIgnoreCase("All"))
+          schema_search = schemas;
+        else
+        {
+          schema_search = new Vector();
+          schema_search.add(schema);
+        }
+
+        try
+        {
+          search(search_gene, schema_search, dao);
+        }
+        catch(SQLException sqlExp)
+        {
+          JOptionPane.showMessageDialog(null, "SQL Problems...\n"
+              + sqlExp.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE);
+          sqlExp.printStackTrace();
+        }
+        catch(ReadFormatException e)
+        {
+          // TODO Auto-generated catch block
+          e.printStackTrace();
+        }
+      }
+    });
+    xbox.add(findButt);
+    xbox.add(Box.createHorizontalGlue());
+    panel.add(xbox, BorderLayout.NORTH);
+    
+    JFrame frame = new JFrame("Feature Search");
+    frame.getContentPane().add(panel);
+    frame.setJMenuBar(getJMenuBar(dao));
+    frame.pack();
+    frame.setVisible(true);
+  }
+
+  /**
+   * Build a <code>JMenuBar</code>.
+   * 
+   * @return a <code>JMenuBar</code>
+   */
+  public JMenuBar getJMenuBar(final ChadoDAO dao)
+  {
+    JMenuBar mbar = new JMenuBar();
+    JMenu file = new JMenu("File");
+    mbar.add(file);
+
+    JMenuItem exit = new JMenuItem("Exit");
+    exit.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent event)
+      {
+        System.exit(0);
+      }
+    });
+    file.add(exit);
+
+    return mbar;
+  }
+
+
+  /**
+   * Search for a feature/gene name from a <code>List</code> of schemas.
+   * 
+   * @param search_gene
+   *          the feature name
+   * @param schema_search
+   *          the <code>List</code> to search
+   * @param dao
+   *          the data access object
+   * @return string array of results
+   * @throws SQLException
+   * @throws ReadFormatException 
+   */
+  public void search(final String search_gene, final List schema_search,
+                     final ChadoDAO dao) throws SQLException, ReadFormatException
+  {
+    Hashtable id_store = new Hashtable();
+    
+    ChadoFeature feature = new ChadoFeature();
+    feature.setUniquename(search_gene);
+    featureList = dao.getLazyFeature(feature,
+                                     schema_search);  
+    
+    ChadoCanonicalGene chado_gene = new ChadoCanonicalGene();
+    
+    if(featureList.size() > 1)
+      System.err.println("More than one feature found!");
+    
+    feature = (ChadoFeature)featureList.get(0);
+    id_store.put(Integer.toString(feature.getId()), feature.getUniquename());
+    
+    int src = feature.getFeatureloc().getSrcfeature_id();
+    
+    ChadoFeature parent = new ChadoFeature();
+    parent.setId(src);
+    List parentList = dao.getLazyFeature(parent, schema_search);
+    parent = (ChadoFeature)parentList.get(0);
+    chado_gene.setSeqlen( parent.getLength() );
+       
+    
+    ByteBuffer buff = new ByteBuffer();
+    DatabaseDocument.chadoToGFF(feature, null, null, null, null, dao, buff);
+    
+    //System.out.println(new String(buff.getBytes())); 
+    
+    GFFStreamFeature gff_gene_feature = new GFFStreamFeature(new String(buff.getBytes()));
+    chado_gene.setGene(gff_gene_feature);
+    
+    // get children of gene
+    List relations = feature.getFeatureRelationshipsForObjectId();
+    
+    for(int i=0;i<relations.size(); i++)
+    {
+      ChadoFeature transcript = new ChadoFeature();
+      transcript.setId( ((ChadoFeatureRelationship)relations.get(i)).getSubject_id() );
+      featureList = dao.getLazyFeature(transcript,
+                                       schema_search);
+      
+      transcript = (ChadoFeature)featureList.get(0);
+      id_store.put(Integer.toString(transcript.getId()), transcript.getUniquename());
+      buff = new ByteBuffer();
+      DatabaseDocument.chadoToGFF(transcript, feature.getUniquename(), 
+                                  null, null, id_store, dao, buff);
+      GFFStreamFeature gff_feature = new GFFStreamFeature(new String(buff.getBytes()));
+      
+      new uk.ac.sanger.artemis.Feature(gff_feature);
+      chado_gene.addTranscript(gff_feature);
+      
+   
+      // get children of transcript - exons and pp
+      List transcipt_relations = transcript.getFeatureRelationshipsForObjectId();
+
+      for(int j=0; j<transcipt_relations.size(); j++)
+      {
+        ChadoFeature child = new ChadoFeature();
+        child.setId( ((ChadoFeatureRelationship)transcipt_relations.get(j)).getSubject_id() );
+        featureList = dao.getLazyFeature(child,
+                                         schema_search);
+      
+        child = (ChadoFeature)featureList.get(0);
+        id_store.put(Integer.toString(child.getId()), child.getUniquename());
+        buff = new ByteBuffer();
+        DatabaseDocument.chadoToGFF(child, transcript.getUniquename(), 
+                                    null, null, id_store, dao, buff);
+        
+        gff_feature = new GFFStreamFeature(new String(buff.getBytes()));
+        new uk.ac.sanger.artemis.Feature(gff_feature);
+        
+        try
+        {
+          if(child.getCvterm().getName().equalsIgnoreCase("polypeptide"))
+            chado_gene.addProtein(transcript.getUniquename(), child);
+          else if(child.getCvterm().getName().equalsIgnoreCase("exon"))
+            chado_gene.addExon(transcript.getUniquename(), child);
+        }
+        catch(InvalidRelationException e)
+        {
+          // TODO Auto-generated catch block
+          e.printStackTrace();
+        }
+
+      }
+    }
+    
+    gff_gene_feature.setChadoGene(chado_gene);
+    
+    GeneBuilderFrame frame = 
+      new GeneBuilderFrame(new uk.ac.sanger.artemis.Feature(gff_gene_feature), 
+                           null, null, null);
+    
+  }
+
+
+  
+  /**
+   * Get the data access object (DAO).
+   * 
+   * @return data access object
+   */
+  private ChadoDAO getDAO() throws java.net.ConnectException, SQLException
+  {
+    if(System.getProperty("ibatis") == null)
+    {
+      if(jdbcDAO == null)
+        jdbcDAO = new JdbcDAO(location, pfield);
+      return jdbcDAO;
+    }
+    else
+    {
+      if(connIB == null)
+        connIB = new IBatisDAO(pfield);
+      return connIB;
+    }
+  }
+
+  /**
+   * Set the database location as:
+   * jdbc:postgresql://localhost:13001/chadoCVS?user=es2
+   * 
+   * @return true if location chosen
+   */
+  protected boolean setLocation()
+  {
+    Container bacross = new Container();
+    bacross.setLayout(new GridLayout(6, 2, 5, 5));
+
+    JLabel lServer = new JLabel("Server : ");
+    bacross.add(lServer);
+    JTextField inServer = new JTextField("localhost");
+    bacross.add(inServer);
+
+    JLabel lPort = new JLabel("Port : ");
+    bacross.add(lPort);
+    JTextField inPort = new JTextField("5432");
+    bacross.add(inPort);
+
+    JLabel lDB = new JLabel("Database : ");
+    bacross.add(lDB);
+    JTextField inDB = new JTextField("chado");
+    bacross.add(inDB);
+
+    JLabel lUser = new JLabel("User : ");
+    bacross.add(lUser);
+    JTextField inUser = new JTextField("afumigatus");
+    bacross.add(inUser);
+
+    JLabel lpasswd = new JLabel("Password : ");
+    bacross.add(lpasswd);
+    pfield = new JPasswordField(16);
+    bacross.add(pfield);
+
+    // given -Dchado=localhost:port/dbname?username
+    if(System.getProperty("chado") != null)
+    {
+      String db_url = System.getProperty("chado").trim();
+      int index;
+      if((index = db_url.indexOf(":")) > -1)
+      {
+        inServer.setText(db_url.substring(0, index));
+        int index2;
+        if((index2 = db_url.indexOf("/")) > -1)
+        {
+          inPort.setText(db_url.substring(index + 1, index2));
+          int index3;
+          if((index3 = db_url.indexOf("?")) > -1)
+          {
+            inDB.setText(db_url.substring(index2 + 1, index3));
+            inUser.setText(db_url.substring(index3 + 1));
+
+            /*
+             * if(!prompt_user) { location = "jdbc:postgresql://"
+             * +inServer.getText().trim()+ ":" +inPort.getText().trim()+ "/"
+             * +inDB.getText().trim()+ "?user=" +inUser.getText().trim(); return
+             * true; }
+             */
+          }
+        }
+      }
+    }
+
+    int n = JOptionPane.showConfirmDialog(null, bacross,
+        "Enter Database Address", JOptionPane.OK_CANCEL_OPTION,
+        JOptionPane.QUESTION_MESSAGE);
+    if(n == JOptionPane.CANCEL_OPTION)
+      return false;
+
+    location = "jdbc:postgresql://" + inServer.getText().trim() + ":"
+        + inPort.getText().trim() + "/" + inDB.getText().trim() + "?user="
+        + inUser.getText().trim();
+
+    return true;
+  }
+
+
+  public static void main(String args[])
+  {
+    new GeneEdit();
+  }
+}
diff --git a/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java b/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java
index 46506c0ce98c8136e38e6acd91359a0c6c905076..504d73869f2672130dac556ba0b2a3d28d926757 100644
--- a/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java
+++ b/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java
@@ -20,28 +20,36 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
- * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java,v 1.2 2006-05-31 15:40:53 tjc Exp $
+ * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java,v 1.3 2006-07-04 15:57:57 tjc Exp $
  */
 
 package uk.ac.sanger.artemis.components.genebuilder;
 
 import javax.swing.*;
 import java.awt.*;
-import java.util.Vector;
+import java.util.List;
+import java.util.Collections;
 import java.awt.geom.RoundRectangle2D;
 
+import uk.ac.sanger.artemis.FeatureSegment;
+import uk.ac.sanger.artemis.FeatureSegmentVector;
+import uk.ac.sanger.artemis.chado.ChadoFeature;
+import uk.ac.sanger.artemis.chado.ChadoFeatureLoc;
 import uk.ac.sanger.artemis.io.Feature;
 import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
 import uk.ac.sanger.artemis.io.InvalidRelationException;
+import uk.ac.sanger.artemis.io.Range;
 
 public class GeneViewerPanel extends JPanel
 {
+  
   private ChadoCanonicalGene chado_gene;
   private int border = 15;
   
   public GeneViewerPanel(final ChadoCanonicalGene chado_gene)
   {
     this.chado_gene = chado_gene;
+    
     Dimension dim = new Dimension(300,300);
     setPreferredSize(dim);
     setBackground(Color.white);
@@ -49,9 +57,11 @@ public class GeneViewerPanel extends JPanel
 
   public void paintComponent(Graphics g)
   {
+    super.paintComponent(g);
     Graphics2D g2d = (Graphics2D)g;
-    Feature embl_gene = chado_gene.getGene();
-    uk.ac.sanger.artemis.Feature gene = (uk.ac.sanger.artemis.Feature)embl_gene.getUserData();
+    Feature embl_gene = (Feature)chado_gene.getGene();
+    uk.ac.sanger.artemis.Feature gene =
+      (uk.ac.sanger.artemis.Feature)embl_gene.getUserData();
     
     setFont(uk.ac.sanger.artemis.Options.getOptions().getFont());
     final FontMetrics fm = this.getFontMetrics(getFont());
@@ -61,6 +71,7 @@ public class GeneViewerPanel extends JPanel
     boolean complement = embl_gene.getLocation().isComplement();
     
     BasicStroke stroke = new BasicStroke(2.f);
+    Stroke original_stroke = g2d.getStroke();
     g2d.setStroke(stroke);
     g2d.setColor( gene.getColour() );
     
@@ -72,11 +83,12 @@ public class GeneViewerPanel extends JPanel
     
     g2d.drawLine(border, ypos, getSize().width - border, ypos);
     
-    Vector transcripts = chado_gene.getTranscripts();
+    List transcripts = chado_gene.getTranscripts();
     Feature embl_transcript;
     uk.ac.sanger.artemis.Feature transcript;
     
-    float fraction = (float)(getSize().width - (2*border))/(float)(end-start);
+    float fraction = (float)(getSize().width - (2*border))/
+                     (float)(end-start);
     for(int i=0; i<transcripts.size(); i++)
     {
       ypos += border;
@@ -95,7 +107,7 @@ public class GeneViewerPanel extends JPanel
       
       try
       {
-        Vector exons = chado_gene.getExonsOfTranscript(
+        List exons = chado_gene.getExonsOfTranscript(
             (String)embl_transcript.getQualifierByName("ID").getValues().get(0));
         
         ypos += border;
@@ -103,26 +115,87 @@ public class GeneViewerPanel extends JPanel
         if(exons == null)
           continue;
         
+        int offset = 0;
+        
+        if(exons.get(0) instanceof ChadoFeature)
+        {
+          int last_ex_start = 0;
+          int last_ex_end   = 0;
+          int last_ypos     = 0;
+          
+          ChadoFeature start_exon = (ChadoFeature)exons.get(0);
+          if(start_exon.getFeatureloc().getStrand() == -1)
+          {
+            if( start_exon.getFeatureloc().getFmin() < 
+                ((ChadoFeature)exons.get(exons.size()-1)).getFeatureloc().getFmin())
+              Collections.reverse(exons);
+          }
+          
+          for(int j=0; j<exons.size(); j++)
+          {           
+            ChadoFeature exon = (ChadoFeature)exons.get(j);
+            
+            int ex_start = border+(int)((exon.getFeatureloc().getFmin()+1-start)*fraction);
+            int ex_end   = border+(int)((exon.getFeatureloc().getFmax()-start)*fraction);
+            
+            Color exon_col = Color.CYAN;
+            
+            offset = getFrameID(chado_gene, exon, j, exons) * getFontHeight() * 2;
+            
+            boolean isForward = false;
+            if(exon.getFeatureloc().getStrand() == 1)
+              isForward = true;
+            
+            drawExons(g2d, ex_start, ex_end, 
+                      last_ex_start, last_ex_end, last_ypos,
+                      offset, ypos, exon_col,
+                      original_stroke, stroke, isForward);
+            
+            last_ex_end   = ex_end;
+            last_ex_start = ex_start;
+            last_ypos   = ypos+offset;
+          }
+          continue;
+        }
+        
+        
         for(int j=0; j<exons.size(); j++)
         {
+          int last_ex_start = 0;
+          int last_ex_end   = 0;
+          int last_ypos     = 0;
+          
           Feature embl_exon = (Feature)exons.get(j);
+          
           uk.ac.sanger.artemis.Feature exon = 
             (uk.ac.sanger.artemis.Feature)embl_exon.getUserData();
-          
-          int ex_start = border+(int)((embl_exon.getFirstBase()-start)*fraction);
-          int ex_end   = border+(int)((embl_exon.getLastBase()-start)*fraction);
-          
-          if(exon.getColour() != null)
-            g2d.setColor( exon.getColour() );
-          RoundRectangle2D e = new RoundRectangle2D.Float(ex_start, ypos, ex_end-ex_start,
-                                                          border, 0, ypos);
-          GradientPaint gp = new GradientPaint(ex_start, ypos, exon.getColour(),
-                                               ex_start, ypos+(border/2), Color.white, true);
-          g2d.setPaint(gp); 
-          g2d.fill(e);
-
-          //g2d.drawLine(ex_start, ypos, ex_end, ypos);
+            
+          FeatureSegmentVector segments = exon.getSegments();
+
+          for(int k=0; k<segments.size(); k++)
+          {
+            FeatureSegment segment = segments.elementAt(k);
+            
+            Range range = segment.getRawRange();
+            offset = segment.getFrameID() * getFontHeight() * 2;
+            
+            int ex_start = border+(int)((range.getStart()-start)*fraction);
+            int ex_end   = border+(int)((range.getEnd()-start)*fraction);
+
+            if(exon.getColour() != null)
+              g2d.setColor( exon.getColour() );
+                       
+            drawExons(g2d, ex_start, ex_end, 
+                     last_ex_start, last_ex_end, last_ypos,
+                     offset, ypos, exon.getColour(),
+                     original_stroke, stroke, segment.isForwardSegment());
+            
+            last_ex_end   = ex_end;
+            last_ex_start = ex_start;
+            last_ypos   = ypos+offset;
+          }
         }
+        
       }
       catch(InvalidRelationException e)
       {
@@ -130,4 +203,157 @@ public class GeneViewerPanel extends JPanel
       }
     }
   }
+  
+  
+  private void drawExons(Graphics2D g2d, int ex_start, int ex_end, 
+                         int last_ex_start, int last_ex_end, int last_ypos,
+                         int offset, int ypos, Color exon_colour,
+                         Stroke original_stroke, Stroke stroke, boolean isForward)
+  {
+    RoundRectangle2D e = new RoundRectangle2D.Float(ex_start, ypos+offset, 
+                                                    ex_end-ex_start,
+                                                    getFontHeight(), 0, ypos+offset);
+    
+    GradientPaint gp = new GradientPaint(ex_start, ypos+offset, 
+                                         exon_colour,
+                                         ex_start, ypos+offset+(getFontHeight()/2), 
+                                         Color.white, true);
+    g2d.setPaint(gp); 
+    g2d.fill(e);
+
+    // draw connections
+    if(last_ex_end != 0 ||
+       last_ex_start != 0)
+    {
+      g2d.setStroke(original_stroke);
+      int ymid;
+      if(last_ypos < ypos+offset)
+        ymid = last_ypos;
+      else
+        ymid = ypos+offset; 
+
+      if(isForward)
+      {      
+        g2d.drawLine(last_ex_end, last_ypos, 
+                     last_ex_end+((ex_start-last_ex_end)/2), ymid-getFontHeight()/2);
+                     g2d.drawLine(last_ex_end+((ex_start-last_ex_end)/2), ymid-getFontHeight()/2, 
+                     ex_start, ypos+offset); 
+      }
+      else
+      {
+        g2d.drawLine(last_ex_start, last_ypos, 
+                     last_ex_start+((ex_end-last_ex_start)/2), ymid-getFontHeight()/2);
+                     g2d.drawLine(last_ex_start+((ex_end-last_ex_start)/2), ymid-getFontHeight()/2, 
+                     ex_end, ypos+offset); 
+      }
+      g2d.setStroke(stroke);  
+    }
+
+  }
+  
+  private int getFrameID(ChadoCanonicalGene chado_gene, ChadoFeature feature, 
+                         int nexon, List exons)
+  {
+    final int position_on_strand;
+    
+    if(feature.getFeatureloc().getStrand() == -1)
+      position_on_strand = chado_gene.getSeqlen()-feature.getFeatureloc().getFmax();
+    else
+      position_on_strand = feature.getFeatureloc().getFmin();
+    
+    // this will be 0, 1 or 2 depending on which frame the segment is in
+    final int start_base_modulo =
+      (position_on_strand + getFrameShift(nexon, exons)) % 3;
+
+    if(feature.getFeatureloc().getStrand() == 1)
+    {
+      switch (start_base_modulo)
+      {
+      case 0:
+        return FeatureSegment.FORWARD_FRAME_1;
+      case 1:
+        return FeatureSegment.FORWARD_FRAME_2;
+      case 2:
+        return FeatureSegment.FORWARD_FRAME_3;
+      }
+    } 
+    else
+    {
+      switch (start_base_modulo)
+      {
+      case 0:
+        return FeatureSegment.REVERSE_FRAME_1;
+      case 1:
+        return FeatureSegment.REVERSE_FRAME_2;
+      case 2:
+        return FeatureSegment.REVERSE_FRAME_3;
+      }
+    }
+
+    return FeatureSegment.NO_FRAME;
+  }
+  
+  
+  /**
+   *  Returns 0, 1 or 2 depending on which translation frame this segment is
+   *  in.  A frame shift of zero means that the bases should be translated
+   *  starting at the start position of this segment, 1 means start
+   *  translating one base ahead of the start position and 2 means start
+   *  translating two bases ahead of the start position.
+   **/
+  private int getFrameShift(int nexon, List exons) 
+  {
+    // find the number of bases in the segments before this one
+    int base_count = 0;
+    int direction  = 0;
+    
+    for(int i = 0; i < exons.size(); ++i) 
+    {
+      ChadoFeature this_feature = (ChadoFeature)exons.get(i);
+      ChadoFeatureLoc featureLoc = this_feature.getFeatureloc();
+ 
+      int this_direction;
+      if(featureLoc.getStrand() == 1)
+        this_direction = 1;
+      else
+        this_direction = -1;
+
+      if(i == nexon) 
+      {
+        if(i != 0 && this_direction != direction)
+          base_count = 0;
+
+        break;
+      }
+      else 
+      {
+        if(i == 0)
+          direction = this_direction;
+        else if(this_direction != direction)
+          base_count = 0;
+
+        base_count += featureLoc.getFmax()-featureLoc.getFmin();
+      }
+    }
+    
+    int codon_start = ((ChadoFeature)exons.get(nexon)).getFeatureloc().getPhase();
+    int mod_value   = (base_count + 3 - codon_start) % 3;
+
+    //System.out.println("GVP mod_value="+mod_value+"  base_count="+base_count + "  codon_start="+codon_start);
+    if(mod_value == 1) 
+      return 2;
+    else if(mod_value == 2)
+      return 1;
+    else 
+      return 0;
+  }
+  
+  
+  
+  private int getFontHeight()
+  {
+    final FontMetrics fm = this.getFontMetrics(getFont());
+    return fm.getHeight();  
+  }
+  
 }
\ No newline at end of file