src/org/gel/mauve/gui/sequence/FeaturePanel.java

Go to the documentation of this file.
00001 package org.gel.mauve.gui.sequence;
00002 
00003 import java.awt.BasicStroke;
00004 import java.awt.BorderLayout;
00005 import java.awt.Color;
00006 import java.awt.Dimension;
00007 import java.awt.event.ActionEvent;
00008 import java.io.IOException;
00009 import java.util.EventListener;
00010 import java.util.Iterator;
00011 import java.util.StringTokenizer;
00012 import java.util.Vector;
00013 
00014 import javax.swing.AbstractAction;
00015 import javax.swing.JDialog;
00016 import javax.swing.JFrame;
00017 import javax.swing.JMenuItem;
00018 import javax.swing.JOptionPane;
00019 import javax.swing.JPopupMenu;
00020 import javax.swing.JTabbedPane;
00021 import javax.swing.ToolTipManager;
00022 import javax.swing.event.EventListenerList;
00023 
00024 import org.biojava.bio.gui.sequence.AbstractBeadRenderer;
00025 import org.biojava.bio.gui.sequence.FeatureBlockSequenceRenderer;
00026 import org.biojava.bio.gui.sequence.FilteringRenderer;
00027 import org.biojava.bio.gui.sequence.MultiLineRenderer;
00028 import org.biojava.bio.gui.sequence.OverlayRendererWrapper;
00029 import org.biojava.bio.gui.sequence.RectangularBeadRenderer;
00030 import org.biojava.bio.gui.sequence.SequenceRenderer;
00031 import org.biojava.bio.gui.sequence.SequenceViewerEvent;
00032 import org.biojava.bio.gui.sequence.SequenceViewerListener;
00033 import org.biojava.bio.gui.sequence.SequenceViewerMotionListener;
00034 import org.biojava.bio.gui.sequence.TranslatedSequencePanel;
00035 import org.biojava.bio.seq.Feature;
00036 import org.biojava.bio.seq.FeatureFilter;
00037 import org.biojava.bio.seq.FeatureHolder;
00038 import org.biojava.bio.seq.Sequence;
00039 import org.biojava.bio.seq.StrandedFeature;
00040 import org.biojava.bio.symbol.Location;
00041 import org.biojava.bio.symbol.LocationTools;
00042 import org.biojava.utils.ChangeVetoException;
00043 import org.gel.mauve.BrowserLauncher;
00044 import org.gel.mauve.DbXrefFactory;
00045 import org.gel.mauve.FilterCacheSpec;
00046 import org.gel.mauve.Genome;
00047 import org.gel.mauve.GenomeBuilder;
00048 import org.gel.mauve.MauveConstants;
00049 import org.gel.mauve.ModelEvent;
00050 import org.gel.mauve.BaseViewerModel;
00051 import org.gel.mauve.gui.MySymbolSequenceRenderer;
00052 import org.gel.mauve.gui.QualifierPanel;
00053 
00061 public class FeaturePanel extends AbstractSequencePanel
00062 {
00063         public static final int DEFAULT_WIDTH = 10000;
00064         public static final int DEFAULT_HEIGHT = 40;
00065     public static final int MAX_FEATURE_DISPLAY_RANGE = 500000;
00066     private TranslatedSequencePanel trans;
00067     private Sequence seq;
00068     private final GenbankMenuItemBuilder gmib = new GenbankMenuItemBuilder();
00069     private final DbXrefMenuItemBuilder dmib = new DbXrefMenuItemBuilder();
00070     private final FeaturePopupMenuBuilder fpmb = new FeaturePopupMenuBuilder();
00071     
00072     public FeaturePanel(Genome genome, BaseViewerModel model)
00073     {
00074         super(model, genome);
00075         setLayout(new BorderLayout());
00076         init();
00077     }
00078 
00079     // This prevents the display of the translatedSequencePanel at the wrong
00080     // scale...
00081     public void setBounds(int arg0, int arg1, int arg2, int arg3)
00082     {
00083         super.setBounds(arg0, arg1, arg2, arg3);
00084 
00085         if (trans != null)
00086             adjustScaleAndTranslation();
00087     }
00088 
00089     private void clearTransPanel()
00090     {
00091         if (trans != null)
00092         {
00093             remove(trans);
00094             trans = null;
00095         }
00096     }
00097 
00098     private void init()
00099     {
00100         seq = getGenome().getAnnotationSequence();
00101 
00102         if (seq == null)
00103         {
00104             clearTransPanel();
00105             return;
00106         }
00107 
00108         if (trans != null)
00109         {
00110             remove(trans);
00111         }
00112         
00113         trans = new TranslatedSequencePanel();
00114         add(trans, BorderLayout.CENTER);
00115 
00116         try
00117         {
00118             trans.setSequence(seq);
00119             trans.setDirection(TranslatedSequencePanel.HORIZONTAL);
00120 
00121             trans.addSequenceViewerMotionListener(new ToolTipMotionListener());
00122             trans.addSequenceViewerListener(new ClickListener());
00123 
00124             MultiLineRenderer multi = new MultiLineRenderer();
00125             FilterCacheSpec[] specs = getGenome().getAnnotationFormat().getFilterCacheSpecs();
00126             FeatureFilterer filterer = FeatureFilterer.getFilterer (model);
00127             MySymbolSequenceRenderer my_symbol = new MySymbolSequenceRenderer();
00128             filterer.addMultiRenderer (multi, my_symbol);
00129             
00130             for (int i = 0; i < specs.length; i++)
00131             {
00132                 FilterCacheSpec spec = specs[i];
00133                 if (spec.getFeatureRenderer() != null)
00134                 {
00135                         makeRenderer (model, multi, spec);
00136                 }
00137             }
00138             
00139             multi.addRenderer(my_symbol);
00140             trans.setRenderer(multi);
00141             
00142             // set the size of this element
00143             Dimension my_size = new Dimension();
00144             my_size.height = DEFAULT_HEIGHT;
00145             my_size.width = DEFAULT_WIDTH;
00146             setNewSize (my_size);
00147         }
00148         catch (ChangeVetoException e)
00149         {
00150             JOptionPane.showMessageDialog(this, "Could not render pane", "Rendering error", JOptionPane.ERROR_MESSAGE);
00151             clearTransPanel();
00152         }
00153         
00154         // add menu item builders
00155         fpmb.addMenuItemBuilder(gmib);
00156         fpmb.addMenuItemBuilder(dmib);
00157     }
00158     
00168         protected static void makeRenderer (BaseViewerModel model,
00169                         MultiLineRenderer multi, FilterCacheSpec spec)
00170                         throws ChangeVetoException {
00171                 FeatureBlockSequenceRenderer fbr = new FeatureBlockSequenceRenderer ();
00172                 fbr.setFeatureRenderer (spec.getFeatureRenderer ());
00173                 fbr.setCollapsing (false);
00174                 OverlayRendererWrapper over = new OverlayRendererWrapper (
00175                                 new FilteringRenderer (fbr, spec.getFilter (), true));
00176                 FeatureFilterer.getFilterer (model).addOverlayRenderer (multi, over);
00177                 multi.addRenderer (over);
00178         }
00179         
00180         public void resizeForMoreFeatures () {
00181                 Dimension my_size = getSize ();
00182                 my_size.height += MauveConstants.FEATURE_HEIGHT;
00183                 setNewSize (my_size);
00184         }
00185         
00186         private void setNewSize (Dimension my_size) {
00187                 setSize (my_size);
00188                 setPreferredSize (my_size);
00189                 setMaximumSize (my_size);
00190                 setMinimumSize (my_size);
00191                 trans.setSize (my_size);
00192                 trans.setPreferredSize (my_size);
00193                 trans.setMaximumSize (my_size);
00194                 trans.setMinimumSize (my_size);
00195         }
00196 
00197     public FeaturePopupMenuBuilder getFeaturePopupMenuBuilder(){ return fpmb; }
00198     public DbXrefMenuItemBuilder getDbXrefMenuItemBuilder(){ return dmib; }
00199     public GenbankMenuItemBuilder getGenbankMenuItemBuilder(){ return gmib; }
00200     
00201     //not being called
00202     private SequenceRenderer barRenderer(String type, Color innerColor, double depth, StrandedFeature.Strand strand) throws ChangeVetoException
00203     {
00204         FeatureFilter filter = new FeatureFilter.And(new FeatureFilter.ByType(type),new FeatureFilter.StrandFilter(strand));
00205         FeatureBlockSequenceRenderer fbr = new FeatureBlockSequenceRenderer();
00206         double offset = strand == StrandedFeature.POSITIVE ? 0 : 5;
00207         if(strand==StrandedFeature.NEGATIVE)
00208                 offset = 10;
00209         RectangularBeadRenderer renderer = new RectangularBeadRenderer(depth, offset, Color.BLACK, innerColor, new BasicStroke());
00210         renderer.setHeightScaling(false);
00211         fbr.setFeatureRenderer(renderer);
00212         fbr.setCollapsing(false);
00213         return new OverlayRendererWrapper(new FilteringRenderer(fbr, filter, true));
00214     }
00215 
00216     private void adjustScaleAndTranslation()
00217     {
00218         if (getSize().width != 0)
00219         {
00220             int width = this.getSize().width;
00221             double scale = (double) width / (double) getGenome().getViewLength();
00222 
00223             if (getGenome().getViewStart() >= seq.length() ||
00224                     getGenome().getViewLength() >= MAX_FEATURE_DISPLAY_RANGE)
00225             {
00226                 // TranslatedSequencePanel can't handle being translated out of
00227                 // visibility, and we want to limit the viewable range for 
00228                 // better performance
00229                 trans.setVisible(false);
00230             }
00231             else
00232             {
00233                 trans.setScale(scale);
00234                 trans.setSymbolTranslation((int) getGenome().getViewStart());
00235                 trans.setVisible(true);
00236             }
00237         }
00238     }
00239 
00240     
00241     private final class DbXrefMenuAction extends AbstractAction
00242         {
00243         protected String url;
00244         protected String db_name;
00245         
00246         DbXrefMenuAction( String url, String db_name, String feature_name ){
00247                 super("View " + feature_name + " in " + db_name);
00248                 this.url = url;
00249                 this.db_name = db_name;
00250         }
00251         public void actionPerformed( ActionEvent e ){
00252                 try{
00253                         BrowserLauncher.openURL(url);
00254                 }catch(IOException ioe){}
00255         }
00256         }
00257 
00258         private final class GenbankMenuAction extends AbstractAction
00259         {
00260         protected int seq_index;
00261         
00262         GenbankMenuAction( int seq_index ){
00263                 super("View GenBank annotation for features at " + seq_index);
00264                 this.seq_index = seq_index;
00265         }
00266 
00267         public void actionPerformed( ActionEvent e ){
00268 
00269             Location loc = LocationTools.makeLocation(seq_index, seq_index);
00270             System.err.println("Starting with " + seq.countFeatures() + " features");
00271             FeatureHolder fh = seq.filter(new FeatureFilter.And(new FeatureFilter.OverlapsLocation(loc), new FeatureFilter.Not(new FeatureFilter.ByType(GenomeBuilder.MAUVE_AGGREGATE))));
00272             System.err.println("Filtering leaves " + fh.countFeatures() + " features.");
00273             if (fh.countFeatures() == 0)
00274                 return;
00275             
00276             JDialog dialog = new JDialog((JFrame) FeaturePanel.this.getTopLevelAncestor(), "Feature Detail", true);
00277 
00278             JTabbedPane tabs = new JTabbedPane();
00279             dialog.getContentPane().add(tabs, BorderLayout.CENTER);
00280 
00281             for (Iterator fi = fh.features(); fi.hasNext();)
00282             {
00283                 Feature f = (Feature) fi.next();
00284                 tabs.add(new QualifierPanel(f));
00285             }
00286             dialog.setSize(800, 800);
00287             dialog.pack();
00288             dialog.setVisible(true);
00289         }
00290         }
00291         
00292         public interface FeatureMenuItemBuilder extends EventListener
00293         {
00294                 public JMenuItem[] getItem(SequenceViewerEvent sve, Genome g, BaseViewerModel model);
00295         }
00296         
00297         public class FeaturePopupMenuBuilder
00298         {
00299             protected EventListenerList builders = new EventListenerList();
00300                 public void addMenuItemBuilder(FeatureMenuItemBuilder fmib)
00301                 {
00302                         builders.add(FeatureMenuItemBuilder.class, fmib);
00303                 }
00304                 public JPopupMenu build(SequenceViewerEvent sve, Genome g, BaseViewerModel model)
00305                 {
00306                         Object[] listeners = builders.getListenerList();
00307                 JPopupMenu leMenu = new JPopupMenu();
00308                 for (int i = listeners.length-2; i>=0; i-=2) {
00309                 if (listeners[i]==FeatureMenuItemBuilder.class) {
00310                         JMenuItem[] items = ((FeatureMenuItemBuilder)listeners[i+1]).getItem(sve, g, model);
00311                         for(int j = 0; j < items.length; j++)
00312                                 leMenu.add(items[j]);
00313                 }
00314             }
00315                         return leMenu;
00316                 }               
00317                 public void removeMenuItemBuilder(FeatureMenuItemBuilder fmib)
00318                 {
00319                         builders.remove(FeatureMenuItemBuilder.class, fmib);
00320                 }
00321         }
00322         
00323         
00324         private class GenbankMenuItemBuilder implements FeatureMenuItemBuilder
00325         {
00326                 public JMenuItem[] getItem(SequenceViewerEvent sve, Genome g, BaseViewerModel model)
00327                 {
00328                 JMenuItem gbk_item = new JMenuItem();
00329                 gbk_item.setAction( new GenbankMenuAction(sve.getPos()) );
00330                 return new JMenuItem[]{gbk_item};
00331                 }
00332         }
00333         private class DbXrefMenuItemBuilder implements FeatureMenuItemBuilder
00334         {
00335                 public JMenuItem[] getItem(SequenceViewerEvent sve, Genome g, BaseViewerModel model)
00336                 {
00337                         Vector items = new Vector();
00338             Object t = sve.getTarget();
00339 
00340             if (t instanceof FeatureHolder)
00341             {
00342                 // we'll be popping up a menu with DB xref options
00343                 // for the user
00344 
00345                 FeatureHolder fh = (FeatureHolder) t;
00346                 for (Iterator fi = fh.features(); fi.hasNext();)
00347                 {
00348                     Feature f = (Feature) fi.next();
00349 
00350                     if (f.getAnnotation().containsProperty("db_xref"))
00351                     {
00352                         String feature_name = f.getType() + " ";
00353                         if( f.getAnnotation().containsProperty("gene") )
00354                                 feature_name += f.getAnnotation().getProperty("gene");
00355                         else if( f.getAnnotation().containsProperty("locus_tag") )
00356                                 feature_name += f.getAnnotation().getProperty("locus_tag");
00357                         else
00358                                 feature_name += f.getLocation();
00359                         String db_xref = f.getAnnotation().getProperty("db_xref").toString();
00360                         if( db_xref.charAt(0) == '[' )
00361                                 db_xref = db_xref.substring(1, db_xref.length() - 1 );
00362 
00363                         // tokenize on ,
00364                         StringTokenizer comma_tok = new StringTokenizer(db_xref, ",");
00365                         // if no tokens then don't bother with a menu
00366                         // just display the GenBank annotation...
00367                         while(comma_tok.hasMoreTokens()){
00368                                 String cur_xref = comma_tok.nextToken();
00369                                 cur_xref = cur_xref.trim();
00370                                 // for each db xref, try to get its URL
00371                                 try{
00372                                         DbXrefFactory dxuf = DbXrefFactory.getInstance();
00373                                         String db_url = dxuf.getDbURL(cur_xref);
00374                                         String db_name = dxuf.getDbName(cur_xref);
00375                                         JMenuItem xref_item = new JMenuItem();
00376                                         xref_item.setAction( new DbXrefMenuAction(db_url,db_name,feature_name) );
00377                                         items.add(xref_item);
00378                                 }catch(DbXrefFactory.UnknownDatabaseException ude)
00379                                                         {
00380                                         System.err.println(ude.getMessage());
00381                                                         }
00382                         }
00383                     }
00384                 }
00385            }
00386            JMenuItem[] items_array = new JMenuItem[items.size()];
00387            items.toArray(items_array);
00388            return items_array;
00389                 }
00390         }
00391 
00392     private final class ClickListener implements SequenceViewerListener
00393     {
00394         public void mouseClicked(SequenceViewerEvent sve)
00395         {            
00396                 JPopupMenu jpm = fpmb.build(sve, getGenome(), model);
00397                 jpm.show(sve.getMouseEvent().getComponent(), sve.getMouseEvent().getX(), sve.getMouseEvent().getY());
00398 
00399         }
00400 
00401         public void mousePressed(SequenceViewerEvent sve)
00402         {
00403             // This space intentionally left blank.
00404         }
00405 
00406         public void mouseReleased(SequenceViewerEvent sve)
00407         {
00408             // This space intentionally left blank.
00409         }
00410     }
00411 
00412     private final class ToolTipMotionListener implements SequenceViewerMotionListener
00413     {
00414         public void mouseDragged(SequenceViewerEvent sve)
00415         {
00416             //This space intentionally left blank.
00417         }
00418 
00419         public void mouseMoved(SequenceViewerEvent sve)
00420         {
00421             Object t = sve.getTarget();
00422 
00423             if (t != null && t instanceof FeatureHolder && 
00424                         ((FeatureHolder) t).countFeatures() > 0) {
00425                 FeatureHolder fh = (FeatureHolder) t;
00426                 ToolTipManager.sharedInstance().registerComponent (trans);
00427                 StringBuffer msg = new StringBuffer("<HTML>");
00428                 for (Iterator fi = fh.features(); fi.hasNext();)
00429                 {
00430                     Feature f = (Feature) fi.next();
00431                     if(f.getAnnotation() == null)
00432                         continue;
00433                     msg.append(f.getType() + " ");
00434                     msg.append(f.getLocation());
00435                     msg.append("<br>");
00436 
00437                     if (f.getAnnotation().containsProperty("gene"))
00438                     {
00439                         msg.append(" <b>");
00440                         msg.append(f.getAnnotation().getProperty("gene"));
00441                         msg.append("</b>");
00442                     }
00443                     else if (f.getAnnotation().containsProperty("locus_tag"))
00444                     {
00445                         msg.append(" <b>");
00446                         msg.append(f.getAnnotation().getProperty("locus_tag"));
00447                         msg.append("</b>");
00448                     }
00449                         
00450                     if (f.getAnnotation().containsProperty("product"))
00451                     {
00452                         msg.append("   ");
00453                         msg.append(f.getAnnotation().getProperty("product"));
00454                     }
00455 
00456                     if (fi.hasNext())
00457                     {
00458                         msg.append("<BR>");
00459                     }
00460                 }
00461                 trans.setToolTipText(msg.toString());
00462             }
00463             else
00464             {
00465                 trans.setToolTipText(null);
00466                 ToolTipManager.sharedInstance().unregisterComponent (trans);
00467             }
00468         }
00469     }
00470 
00471     public void viewableRangeChanged(ModelEvent event)
00472     {
00473         if (trans != null)
00474         {
00475             adjustScaleAndTranslation();
00476         }
00477     }
00478     
00479     public void genomesReordered(ModelEvent event)
00480     {
00481         // Ignored
00482     }
00483 }

Generated on Mon Aug 19 06:03:42 2013 for Mauve by doxygen 1.3.6