diff --git a/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java b/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..585621dd5fd6b361111070aef3cfa135defec7de
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java
@@ -0,0 +1,108 @@
+/* GeneBuilderFrame.java
+ *
+ * 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.
+ *
+ * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneBuilderFrame.java,v 1.1 2006-05-31 09:49:07 tjc Exp $
+ */
+
+package uk.ac.sanger.artemis.components.genebuilder;
+
+import javax.swing.*;
+import java.awt.*;
+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.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
+{
+  
+  public GeneBuilderFrame(final Feature gene_feature)
+  {
+    super("Artemis Gene Builder: " + gene_feature.getIDString() +
+          (gene_feature.isReadOnly() ?
+          "  -  (read only)" :
+          ""));
+    
+    QualifierTextArea qualifier_text_area = new QualifierTextArea();
+    GFFStreamFeature gff_feature = (GFFStreamFeature)gene_feature.getEmblFeature();
+    GeneComponentTree tree = new GeneComponentTree(gff_feature.getChadoGene(),
+                                                   qualifier_text_area);
+    getContentPane().add(new JScrollPane(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));
+    
+    getContentPane().add(new JScrollPane(qualifier_text_area), BorderLayout.SOUTH);
+    
+    pack();
+    setVisible(true);
+  }
+
+  /**
+   *  Return a string containing one qualifier per line.  These are the
+   *  original qualifiers, not the qualifiers from the qualifier_text_area.
+   **/
+  protected static String getQualifierString(final Feature feature) 
+  {
+    final StringBuffer buffer = new StringBuffer();
+    final QualifierVector qualifiers = feature.getQualifiers();
+
+    for(int qualifier_index = 0; qualifier_index < qualifiers.size();
+        ++qualifier_index) 
+    {
+      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");
+      }
+    }
+
+    return buffer.toString();
+  }
+  
+  /**
+   *  Return the EntryInformation object of the entry containing the feature.
+   **/
+  protected static EntryInformation getEntryInformation(final Feature feature) 
+  {
+    return feature.getEntry().getEntryInformation();
+  }
+
+}
\ 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
new file mode 100644
index 0000000000000000000000000000000000000000..b156fd91db9e57ffccb29d999ed62b967685bfe7
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java
@@ -0,0 +1,136 @@
+/* GeneComponentTree.java
+ *
+ * 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.
+ *
+ * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneComponentTree.java,v 1.1 2006-05-31 09:49:07 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 javax.swing.*;
+import javax.swing.event.*;
+
+import javax.swing.tree.*;
+import java.util.Vector;
+
+/**
+ * Tree to display a gene hierarchy.
+ */
+public class GeneComponentTree extends JTree
+{
+  
+  public GeneComponentTree(final ChadoCanonicalGene chado_gene,
+                           final QualifierTextArea qualifier_text_area)
+  {
+    final Feature gene = chado_gene.getGene();
+    final String gene_id;
+    try
+    {
+      gene_id = (String)gene.getQualifierByName("ID").getValues().get(0);
+      DefaultMutableTreeNode top =
+           new DefaultMutableTreeNode(gene_id);
+
+      createNodes(top, chado_gene);
+      DefaultTreeModel model = new DefaultTreeModel(top);
+      setModel(model);
+    }
+    catch(InvalidRelationException e)
+    {
+      e.printStackTrace();
+    }
+    
+    //Listen for when a file is selected
+    addTreeSelectionListener(new TreeSelectionListener()
+    {
+      public void valueChanged(TreeSelectionEvent e)
+      {
+        DefaultMutableTreeNode node = 
+          (DefaultMutableTreeNode)GeneComponentTree.this.getLastSelectedPathComponent();
+        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() ) );
+      }
+    });
+    
+  }
+  
+  /**
+   * Build the node hierarchy for this gene, i.e. transcript, exons, 
+   * CDS, polypeptide.
+   * @param gene_node
+   * @param chado_gene
+   * @throws InvalidRelationException
+   */
+  private void createNodes(final DefaultMutableTreeNode gene_node,
+                           final ChadoCanonicalGene chado_gene) 
+          throws InvalidRelationException 
+  {
+    Vector transcripts = chado_gene.getTranscripts();
+    Vector exons;
+    Feature transcript;
+    Feature exon;
+    Feature protein;
+    String transcript_id;
+    String exon_id;
+    String protein_id;
+    DefaultMutableTreeNode transcript_node;
+    DefaultMutableTreeNode exon_node;
+    DefaultMutableTreeNode protein_node;
+    
+    for(int i=0; i<transcripts.size(); i++)
+    {
+      transcript = (Feature)transcripts.get(i);
+      transcript_id = (String)transcript.getQualifierByName("ID").getValues().get(0);
+      transcript_node = new DefaultMutableTreeNode(transcript_id);
+      gene_node.add(transcript_node);
+      
+      exons = chado_gene.getExonsOfTranscript(transcript_id);
+      if(exons == null)
+        continue;
+
+      for(int j=0; j<exons.size(); j++)
+      {
+        exon = (Feature)exons.get(i);
+        exon_id = (String)exon.getQualifierByName("ID").getValues().get(0);
+        exon_node = new DefaultMutableTreeNode(exon_id);
+        transcript_node.add(exon_node);
+      }
+      
+      protein = chado_gene.getProteinOfTranscript(transcript_id);
+      if(protein == null)
+        continue;
+      
+      protein_id = (String)protein.getQualifierByName("ID").getValues().get(0);
+      protein_node = new DefaultMutableTreeNode(protein_id);
+      
+      transcript_node.add(protein_node);
+    }
+  }
+  
+}
diff --git a/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java b/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a24dd22200c5e1bd7efbbba8935cf54c74e2677
--- /dev/null
+++ b/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java
@@ -0,0 +1,128 @@
+/* GeneViewerPanel
+ *
+ * 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.
+ *
+ * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/GeneViewerPanel.java,v 1.1 2006-05-31 09:49:07 tjc Exp $
+ */
+
+package uk.ac.sanger.artemis.components.genebuilder;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Vector;
+import java.awt.geom.RoundRectangle2D;
+
+import uk.ac.sanger.artemis.io.Feature;
+import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
+import uk.ac.sanger.artemis.io.InvalidRelationException;
+
+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);
+  }
+
+  public void paintComponent(Graphics 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();
+    
+    setFont(uk.ac.sanger.artemis.Options.getOptions().getFont());
+    final FontMetrics fm = this.getFontMetrics(getFont());
+
+    int start = embl_gene.getFirstBase();
+    int end   = embl_gene.getLastBase();
+    boolean complement = embl_gene.getLocation().isComplement();
+    
+    BasicStroke stroke = new BasicStroke(2.f);
+    g2d.setStroke(stroke);
+    g2d.setColor( gene.getColour() );
+    
+    int ypos = border;
+    
+    ypos += fm.getHeight();
+    g2d.drawString(gene.getIDString(), border, ypos);
+    ypos += fm.getHeight();
+    
+    g2d.drawLine(border, ypos, getSize().width - border, ypos);
+    
+    Vector transcripts = chado_gene.getTranscripts();
+    Feature embl_transcript;
+    uk.ac.sanger.artemis.Feature transcript;
+    
+    float fraction = (float)(getSize().width - (2*border))/(float)(end-start);
+    for(int i=0; i<transcripts.size(); i++)
+    {
+      ypos += border;
+      embl_transcript  = (Feature)transcripts.get(i);
+      transcript = (uk.ac.sanger.artemis.Feature)embl_transcript.getUserData();
+      
+      int t_start = border+(int)((embl_transcript.getFirstBase()-start)*fraction);
+      int t_end   = border+(int)((embl_transcript.getLastBase()-start)*fraction);
+      
+      ypos += fm.getHeight();
+      g2d.drawString(transcript.getIDString(), border, ypos);
+      ypos += fm.getHeight();
+      
+      g2d.setColor( transcript.getColour() );
+      g2d.drawLine(t_start, ypos, t_end, ypos);
+      
+      try
+      {
+        Vector exons = chado_gene.getExonsOfTranscript(
+            (String)embl_transcript.getQualifierByName("ID").getValues().get(0));
+        
+        ypos += border;
+        for(int j=0; j<exons.size(); j++)
+        {
+          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);
+          
+          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);
+        }
+      }
+      catch(InvalidRelationException e)
+      {
+        e.printStackTrace();
+      }
+    }
+  }
+}
\ No newline at end of file