001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022package org.biojava.bio.gui;
023
024import java.util.ArrayList;
025import java.util.Iterator;
026
027import javax.swing.JTree;
028import javax.swing.event.TreeModelListener;
029import javax.swing.tree.TreeModel;
030import javax.swing.tree.TreePath;
031
032import org.biojava.bio.Annotation;
033import org.biojava.bio.BioException;
034import org.biojava.bio.seq.Feature;
035import org.biojava.bio.seq.FeatureFilter;
036import org.biojava.bio.seq.FeatureHolder;
037import org.biojava.bio.seq.Sequence;
038import org.biojava.bio.seq.SequenceIterator;
039import org.biojava.bio.seq.db.SequenceDB;
040
041/**
042 * FeatureTree is GUI tree to display the features and annotations
043 * of the sequences in a <code>SequenceDB</code> Nested Features are
044 * displayed as expandable leaves.
045 *
046 * <p>Copyright:    Copyright (c) 2002</p>
047 * <p>Company:      AgResearch</p>
048 *
049 * @author Mark Schreiber
050 * @version 1.0
051 */
052
053public class FeatureTree extends JTree{
054  private String root = "DB";
055  private ArrayList seqs = new ArrayList();
056
057  /**
058   * Create a new FeatureTree
059   */
060  public FeatureTree() {
061    super();
062    this.setModel(new FeatureModel(root));
063  }
064
065  /**
066   * Use this method to provide the sequences for the tree to work with.
067   * @param db A database of <CODE>Sequence</CODE>s to display
068   * @throws org.biojava.bio.BioException if information cannot be retrieved from <CODE>db</CODE>
069   */
070  public void setSequenceDB(SequenceDB db) throws BioException{
071    for(SequenceIterator i = db.sequenceIterator(); i.hasNext();){
072      seqs.add(i.nextSequence());
073    }
074    this.expandRow(0);
075    this.repaint();
076  }
077
078  /**
079   * Labels <code>Sequence</code> objects with their name, <code>Annotations</code> with
080   * the tag Annotations, <code>Features</code> with the tag Features and other objects
081   * with the <code>toString</code> value.
082   */
083  public String convertValueToText(Object value, boolean selected,
084                                     boolean expanded, boolean leaf, int row,
085                                     boolean hasFocus) {
086      if(value instanceof Sequence) return ((Sequence)value).getName();
087      if(value instanceof Annotation) return "Annotations";
088      if(value instanceof Feature) return value.toString();
089      if(value instanceof FeatureHolder) return "Features";
090      else if(value != null) return value.toString();
091      return "";
092    }
093
094  /**
095   * The model used by the FeatureTree
096   */
097  class FeatureModel implements TreeModel {
098    protected String root;
099
100    public FeatureModel(String root){
101      this.root = root;
102    }
103
104    public Object getRoot(){ return root;}
105
106    public boolean isLeaf(Object node){
107      if(node.equals(getRoot())){
108        if(seqs.size()==0) return true;
109        else return false;
110      }
111      if(node instanceof FeatureHolder){
112        return false;
113      }
114      if(node.equals(Annotation.EMPTY_ANNOTATION)){
115        return true;
116      }
117      if(node instanceof String) return true;
118      return false;
119    }
120
121    public int getChildCount(Object parent){
122      if(parent.equals(this.getRoot())) return seqs.size();
123      else if(parent instanceof Sequence){
124        return 3; //annotation + feature holder + SymbolList
125      }
126      if(parent instanceof Annotation){
127        return ((Annotation)parent).keys().size();
128      }
129      if(parent instanceof Feature){
130        return 3;//for annotation + Sequence + Nested Features
131      }
132      if(parent instanceof FeatureHolder){
133        return ((FeatureHolder)parent).countFeatures();
134      }
135
136      return 0;
137    }
138
139    public Object getChild(Object parent, int index){
140     if(parent.equals(getRoot())){
141       return ((Sequence)seqs.get(index));
142     }else if(parent instanceof Sequence){
143       if(index == 0) return ((Sequence)parent).getAnnotation();
144       if(index == 1) return ((Sequence)parent).filter(FeatureFilter.all,false);
145       else return ((Sequence)parent).seqString();
146     }else if(parent instanceof Feature){
147       if(index == 0)return ((Feature)parent).getAnnotation();
148       if(index == 1)return ((Feature)parent).filter(FeatureFilter.all,false);
149       else return ((Feature)parent).getSymbols().seqString();
150
151     }else if(parent instanceof FeatureHolder){
152       ArrayList al = new ArrayList();
153       for(Iterator i = ((FeatureHolder)parent).features(); i.hasNext();){
154         al.add(i.next());
155       }
156
157       Feature f = (Feature)al.get(index);
158       return f;
159     }else{//parent must be Annotation
160       ArrayList al = new ArrayList();
161       for(Iterator i = ((Annotation)parent).keys().iterator(); i.hasNext();){
162         Object key = i.next();
163         Object value = ((Annotation)parent).getProperty(key);
164         al.add(key.toString()+" : "+value.toString());
165       }
166       return al.get(index);
167     }
168    }
169
170    public int getIndexOfChild(Object parent, Object child){
171     if(parent.equals(getRoot())){
172       for(int i = 0; i < seqs.size(); i++){
173         if(seqs.get(i).equals(child)) return i;
174       }
175     }else if(parent instanceof Sequence || parent instanceof Feature){
176       if(child instanceof Annotation)return 0;
177       if(child instanceof FeatureHolder)return 1;
178       else return 2;
179     }else if(parent instanceof FeatureHolder){
180       ArrayList al = new ArrayList();
181       for(Iterator i = ((FeatureHolder)parent).features(); i.hasNext();){
182         al.add(i.next());
183       }
184       for(int i = 0; i < al.size(); i++){
185         if(al.get(i).equals(child)) return i;
186       }
187     }else if(parent instanceof Annotation){
188              ArrayList al = new ArrayList();
189       for(Iterator i = ((Annotation)parent).keys().iterator(); i.hasNext();){
190         Object key = i.next();
191         Object value = ((Annotation)parent).getProperty(key);
192         al.add(key.toString()+" : "+value.toString());
193       }
194       for (int i = 0; i < al.size(); i++) {
195         if(child.equals(al.get(i))) return i;
196       }
197
198     }
199      return -1;
200    }
201
202    public void valueForPathChanged(TreePath path, Object newValue){}
203    public void removeTreeModelListener(TreeModelListener l){}
204    public void addTreeModelListener(TreeModelListener l){}
205  }
206}