src/org/gel/mauve/gui/SequenceNavigator.java

Go to the documentation of this file.
00001 package org.gel.mauve.gui;
00002 
00003 import java.awt.BorderLayout;
00004 import java.awt.Color;
00005 import java.awt.Component;
00006 import java.awt.Dimension;
00007 import java.awt.Frame;
00008 import java.awt.Toolkit;
00009 import java.awt.event.ActionListener;
00010 import java.awt.event.ActionEvent;
00011 import java.awt.event.KeyListener;
00012 import java.awt.event.KeyEvent;
00013 import java.awt.event.WindowAdapter;
00014 import java.awt.event.WindowEvent;
00015 import java.util.Collections;
00016 import java.util.Iterator;
00017 import java.util.LinkedList;
00018 import java.util.Vector;
00019 
00020 import javax.swing.*;
00021 import javax.swing.event.AncestorEvent;
00022 import javax.swing.event.AncestorListener;
00023 
00024 import org.gel.mauve.Genome;
00025 import org.gel.mauve.BaseViewerModel;
00026 import org.gel.mauve.MauveConstants;
00027 import org.gel.mauve.SeqFeatureData;
00028 import org.gel.mauve.gui.navigation.NavigationPanel;
00029 import org.gel.mauve.gui.navigation.SearchResultPanel;
00030 import org.gel.mauve.gui.sequence.RRSequencePanel;
00031 import org.gel.mauve.gui.sequence.SeqPanel;
00032 
00033 import org.biojava.bio.seq.Feature;
00034 
00035 
00045 public class SequenceNavigator extends JSplitPane implements ActionListener, 
00046                 KeyListener, MauveConstants {
00047 
00051         protected Component parent_component;   
00052         protected RearrangementPanel rrpanel;   
00053         protected BaseViewerModel data_model;   
00057         protected JFrame frame;
00058         
00062         protected JComboBox genomes;
00063         
00067         protected LinkedList nav_panels;
00068         
00072         protected JButton search;
00073         protected JButton cancel;
00074         protected JButton add;
00075         
00079         protected JButton reset;
00080         
00084         protected JPanel nav_panel_holder;
00085         
00089         protected SearchResultPanel result_pane;
00090         
00094         protected JCheckBox clear;
00095         
00099         protected JScrollPane result_scroller;
00100         
00104         protected JScrollPane nav_scroll;
00105         protected LinkedList window_listeners;
00106         protected WindowAdapter adapt;
00107         
00112         protected AncestorListener ancestListener;
00113         
00117         protected Vector genome_choices;
00118         
00122         public static int MAX_HEIGHT = 400;
00123         
00127          public static int MAX_WIDTH = 850;
00128 
00129         
00133         static {
00134                 READ_TO_ACTUAL.put(NAME, LOC_NAME);
00135                 READ_TO_ACTUAL.put(PRODUCT, PRODUCT_NAME);
00136                 READ_TO_ACTUAL.put(ID, ID_NUMBER);
00137                 READ_TO_ACTUAL.put(GO, GO_FEATS);
00138                 ANNOTATION_KEYS.add ("biovar");
00139                 ANNOTATION_KEYS.add ("codon_start");
00140                 ANNOTATION_KEYS.add ("db_xref");
00141                 ANNOTATION_KEYS.add ("function");
00142                 ANNOTATION_KEYS.add ("gene");
00143                 ANNOTATION_KEYS.add ("insertion_seq");
00144                 ANNOTATION_KEYS.add ("internal_data");
00145                 ANNOTATION_KEYS.add ("locus_tag");
00146                 ANNOTATION_KEYS.add ("mol_type");
00147                 ANNOTATION_KEYS.add ("note");
00148                 ANNOTATION_KEYS.add ("organism");
00149                 ANNOTATION_KEYS.add ("product");
00150                 ANNOTATION_KEYS.add ("protein_id");
00151                 ANNOTATION_KEYS.add ("pseudo");
00152                 ANNOTATION_KEYS.add ("strain");
00153                 ANNOTATION_KEYS.add ("transl_except");
00154                 ANNOTATION_KEYS.add ("transl_table");
00155                 ANNOTATION_KEYS.add ("translation");
00156         }
00157         
00161         private Boolean current_search = Boolean.FALSE;
00162         
00163         
00169         public SequenceNavigator (MauveFrame frame) {
00170                 super ();
00171                 parent_component = frame.getRootPane();
00172                 data_model = frame.getModel();
00173                 nav_panels = new LinkedList ();
00174                 rrpanel = frame.getRearrangementPanel ();
00175                 initGUI ();
00176         }
00177         public SequenceNavigator (Component parent, RearrangementPanel rrpanel, BaseViewerModel dataModel) 
00178         {
00179                 super ();
00180                 parent_component = parent;
00181                 data_model = dataModel;
00182                 this.rrpanel = rrpanel;
00183                 nav_panels = new LinkedList ();
00184                 initGUI ();
00185         }
00186         
00191         private void initGUI () {
00192                 makeFrame ();
00193                 //setOneTouchExpandable (true);
00194                 setResizeWeight (0);
00195                 JPanel left = new JPanel (new BorderLayout (BORDER, BORDER));
00196                 //makes panel for choosing genome
00197                 JPanel top1 = new JPanel ();
00198                 top1.setLayout(new BoxLayout (top1, BoxLayout.X_AXIS));
00199                 top1.add (new JLabel ("Choose Genome:"));
00200                 genomes = new JComboBox ();
00201                 loadGenomeList ();
00202                 top1.add (genomes);
00203                 left.add (top1, BorderLayout.NORTH);    
00204                 left.setBorder (BorderFactory.createEmptyBorder(3, 3, 3, 3));
00205                 JPanel middle = new JPanel (new BorderLayout ());
00206                 nav_panel_holder = new JPanel ();
00207                 middle.setBorder (BorderFactory.createTitledBorder(
00208                                 BorderFactory.createCompoundBorder (BorderFactory.createLineBorder (Color.black),
00209                                                 BorderFactory.createEmptyBorder(BORDER, BORDER, 0, BORDER)), 
00210                                                 "Find features with the following qualifying information:"));
00211                 nav_panel_holder.setLayout (new BoxLayout (nav_panel_holder, BoxLayout.Y_AXIS));
00212                 result_scroller = result_pane.getScrollPane ();
00213                 nav_scroll = new JScrollPane (nav_panel_holder);
00214                 new NavigationPanel (this);
00215                 middle.add (nav_scroll, BorderLayout.CENTER);
00216                 left.add (middle, BorderLayout.CENTER);
00217                 makeBottomPanel (left);
00218                 setLeftComponent (left);
00219                 setRightComponent (result_scroller);
00220                 frame.getContentPane ().add (this);
00221                 Dimension preferred = middle.getPreferredSize ();
00222                 preferred.width += 6;
00223                 preferred.height += 6;
00224                 left.setMinimumSize (new Dimension (preferred.width,
00225                                 left.getPreferredSize ().height));
00226                 left.setMaximumSize(new Dimension (preferred.width, -1));
00227                 frame.pack ();
00228                 reloadGUI ();
00229                 moveFromBehind ();
00230         }
00231         
00237         private void makeFrame () {
00238                 window_listeners = new LinkedList ();
00239                 frame = new JFrame ("Sequence Navigator");
00240                 frame.setIconImage(MauveFrame.mauve_icon.getImage());
00241                 ((JPanel) frame.getContentPane ()).setBorder (
00242                                 BorderFactory.createEmptyBorder(10, 10, 10, 10));
00243                 adapt = new WindowAdapter () {
00244                         public void windowClosing (WindowEvent e) {
00245                                 frame.setVisible (false);
00246                         }
00247                 };
00248                 ancestListener = new AncestorListener(){
00249                         public void ancestorMoved(AncestorEvent ae){}
00250                         public void ancestorAdded(AncestorEvent ae){}
00251                         public void ancestorRemoved(AncestorEvent ae){
00252                                 frame.setVisible(false);
00253                         }
00254                 };
00255                 if(parent_component instanceof Frame)
00256                         ((Frame)parent_component).addWindowListener(adapt);
00257                 else if(parent_component instanceof JComponent)
00258                         ((JComponent)parent_component).addAncestorListener(ancestListener);
00259                 /*mauve_frame.addWindowListener(new WindowAdapter () {
00260                         public void windowClosing (WindowEvent e) {
00261                                 frame.setVisible (false);
00262                         }
00263                 });*/
00264         }
00265         
00271         private void makeBottomPanel (JPanel holder) {
00272                 search = new JButton ("Search");
00273                 cancel = new JButton ("Close");
00274                 add = new JButton ("Add Constraint");
00275                 reset = new JButton ("Reset Constraints");
00276                 JPanel all = new JPanel (new BorderLayout ());
00277                 clear = new JCheckBox ("Clear previous results when adding new");
00278                 clear.setSelected(true);
00279                 JPanel bottom = new JPanel ();
00280                 bottom.add(add);
00281                 bottom.add(reset);
00282                 bottom.add (search);
00283                 bottom.add (cancel);
00284                 search.addActionListener (this);
00285                 search.addKeyListener (this);
00286                 cancel.addActionListener (this);
00287                 add.addActionListener (this);
00288                 reset.addActionListener (this);
00289                 JPanel temp = new JPanel ();
00290                 temp.add (clear);
00291                 all.add(temp, BorderLayout.NORTH);
00292                 all.add(bottom, BorderLayout.SOUTH);
00293                 //setBorder (BorderFactory.createEmptyBorder (10, 10, 10, 10));
00294                 holder.add (all, BorderLayout.SOUTH);
00295         }
00296         
00302         //not sure how well this works in all cases, has done what I need so far
00303         protected void moveFromBehind () {
00304                 Dimension needed = frame.getSize();
00305                 int area = 0;
00306                 Dimension total = Toolkit.getDefaultToolkit().getScreenSize();
00307                 Dimension taken = parent_component.getSize ();
00308                 int extra = total.width - taken.width;
00309                 int x = 0;
00310                 int y = 0;
00311                 if (extra >= needed.width)
00312                         x = taken.width;
00313                 else {
00314                         area = extra * needed.height;
00315                         extra = total.height - taken.height;
00316                         if (extra >= needed.height)
00317                                 y = taken.height;
00318                         else if (area > extra * needed.width)
00319                                 x = total.width - needed.width;
00320                         else
00321                                 y = total.height - needed.height;
00322                 }
00323                 frame.setLocation(x, y);
00324         }
00325         
00330         public void loadGenomeList () {
00331                 genome_choices = SeqFeatureData.userSelectableGenomes (data_model, true, true);
00332                 genomes.setRenderer (GenomeCellRenderer.getListCellRenderer ());
00333                 genomes.setModel (new DefaultComboBoxModel (genome_choices));
00334                 result_pane = new SearchResultPanel (SeqFeatureData.userSelectableGenomes (
00335                                 data_model, false, false), this);
00336         }
00337         
00343         public boolean shouldClear () {
00344                 return clear.isSelected ();
00345         }
00346         
00350         public void addNavigationPanel (NavigationPanel pane) {
00351                 nav_panels.addFirst (pane);
00352                 nav_panel_holder.add (pane);
00353                 pane.setMaximumSize (pane.getPreferredSize());
00354                 reloadGUI ();
00355                         
00356         }
00357         
00361         public void removeNavigationPanel (NavigationPanel pane) {
00362                 if (nav_panels.size() != 1) {
00363                         nav_panels.remove(pane);
00364                         nav_panel_holder.remove(pane);
00365                         reloadGUI ();
00366                 }
00367         }
00368         
00372         public void reset () {
00373                 Object [] panels = nav_panels.toArray();
00374                 for (int i = 0; i < panels.length - 1; i++)
00375                         removeNavigationPanel ((NavigationPanel) panels [i]);
00376         }
00377         
00383         public void showNavigator () {
00384                 frame.setVisible (true);
00385         }
00386         
00387         
00398         public void actionPerformed (final ActionEvent e) {
00399                 if (e.getSource () == search) {
00400                         Thread t = new Thread () {
00401                                 public void run () {
00402                                         synchronized (current_search) {
00403                                                 if (current_search == Boolean.FALSE) {
00404                                                         current_search = Boolean.TRUE;
00405                                                 }
00406                                                 else
00407                                                         return;
00408                                         }
00409                                         try {
00410                                                 doNavigation ();
00411                                         } catch (Exception e) {
00412                                                 e.printStackTrace ();
00413                                         }
00414                                         current_search = Boolean.FALSE;
00415                                 }
00416                         };
00417                         //threads.add(t);
00418                         t.start ();
00419                 }
00420                 if (current_search == Boolean.FALSE) {
00421                         if (e.getSource () == add)
00422                                 new NavigationPanel (SequenceNavigator.this);
00423                         else if (e.getSource() == cancel)
00424                                 frame.setVisible (false);
00425                         else if (e.getSource () == reset)
00426                                 reset ();
00427                 }
00428         }
00429         
00436         public void reloadGUI () {
00437                 Dimension size = frame.getSize ();
00438                 expandIfNecessary (nav_scroll, size);
00439                 expandIfNecessary (result_scroller, size);
00440                 size.width = (size.width > MAX_WIDTH) ? MAX_WIDTH : size.width;
00441                 size.height = (size.height > MAX_HEIGHT) ? MAX_HEIGHT : size.height;
00442                 frame.setSize(size);
00443                 revalidate ();
00444                 repaint ();
00445         }
00446         
00447         
00456         public static void expandIfNecessary (JScrollPane pane, Dimension size) {
00457                 JViewport port = pane.getViewport ();
00458                 Dimension preferred = port.getView ().getPreferredSize ();
00459                 Dimension actual = port.getSize ();
00460                 if (preferred.width > actual.width)
00461                         size.width += preferred.width - actual.width;
00462                 if (preferred.height > actual.height)
00463                         size.height += preferred.height - actual.height;
00464         }
00465 
00469         public void keyPressed (KeyEvent e) {
00470         }
00471         
00475         public void keyReleased (KeyEvent e) {
00476         }
00477         
00482         public void keyTyped (KeyEvent e) {
00483                 if (e.getKeyChar () == '\n') {
00484                         ActionEvent ae = new ActionEvent (search, ActionEvent.ACTION_PERFORMED, null);
00485                         actionPerformed (ae);
00486                 }
00487         }
00488         
00494         public void makeConstraintVisible (NavigationPanel panel) {
00495                 nav_scroll.getViewport ().scrollRectToVisible (panel.getBounds ());
00496         }
00497 
00506         public int getValidCount () {
00507                 int count = 0;
00508                 boolean hole = false;
00509                 Object [] items = nav_panels.toArray ();
00510                 for (int i = items.length - 1; i >= 0; i--) {
00511                         NavigationPanel pan = (NavigationPanel) items [i];
00512                         if (pan.dataValid ()) {
00513                                 if (hole) {
00514                                         JOptionPane.showMessageDialog(frame, "Missing or invalid data.\n" +
00515                                                         "Can't perform search.", "Navigation Error", JOptionPane.ERROR_MESSAGE);
00516                                         return 0;
00517                                 }
00518                                 else
00519                                         count++;
00520                         }
00521                         else
00522                                 hole = true;
00523                 }
00524                 return count;
00525         }
00526         
00527         
00537         public static void goToSeqPos (Component parentComponent, BaseViewerModel dataModel, RearrangementPanel rrpanel) {
00538                 Genome [] chosen = SeqFeatureData.userSelectedGenomes (parentComponent, 
00539                                 dataModel, false, false);
00540                 if (chosen != null) {
00541                         long pos = -1;
00542                         do {
00543                                 try {
00544                                         String input = JOptionPane.showInputDialog (parentComponent, 
00545                                         "Enter sequence coordinate to jump to...");
00546                                         if (input != null)
00547                                                 pos = Long.parseLong (input);
00548                                         else
00549                                                 break;
00550                                 } catch (NumberFormatException e) {
00551                                         JOptionPane.showMessageDialog(parentComponent, "Invalid position entered",
00552                                                         "Invalid Data", JOptionPane.ERROR_MESSAGE);
00553                                 }
00554                         } while (pos == -1);
00555                         if (pos != -1)
00556                                 goToPosition (pos, chosen [0], rrpanel);
00557                 }
00558         }
00559         
00560         
00567         public void goToFeatureByName () {
00568                 Genome [] chosen = SeqFeatureData.userSelectedGenomes (
00569                                 parent_component, data_model, true, true);
00570                 if (chosen != null) {
00571                         String input = JOptionPane.showInputDialog (parent_component, 
00572                         "Enter name of desired feature. . .");
00573                         if (input != null) {
00574                                 String [][] data = new String [1][3];
00575                                 data [0][FIELD] = LOC_NAME;
00576                                 data [0][VALUE] = input;
00577                                 data [0][EXACT] = Boolean.toString(false);
00578                                 int count = 0;
00579                                 LinkedList first = null;
00580                                 LinkedList [] tree_data = SeqFeatureData.findFeatures (chosen, data);
00581                                 for (int i = 0; i < chosen.length; i++) {
00582                                         Object genome = tree_data [i].removeFirst ();
00583                                         SeqFeatureData.removeLocationDuplicates (tree_data [i]);
00584                                         count += tree_data [i].size();
00585                                         tree_data [i].addFirst (genome);
00586                                         if (count == 1) {
00587                                                 first = tree_data [i];
00588                                         }
00589                                 }
00590                                 if (count == 1)
00591                                         displayFeature ((Feature) first.get(1), (Genome) first.getFirst());
00592                                 else if (count == 0) {
00593                                         JOptionPane.showMessageDialog(parent_component, 
00594                                                         "No Features were found with specified name.");
00595                                 }
00596                                 else {
00597                                         frame.setVisible(true);
00598                                         result_pane.displayFeatures(tree_data);
00599                                 }
00600                         }
00601                 }
00602                 
00603         }
00604         
00610         protected void doNavigation () {
00611                 int index = genomes.getSelectedIndex();
00612                 int valid = getValidCount ();
00613                 if (valid > 0) {
00614                         result_pane.waitForResults ();
00615                         String [][] criteria = new String [valid][3];
00616                         for (int i = 0; i < criteria.length; i++)
00617                                 criteria [i] = ((NavigationPanel) nav_panels.get(
00618                                                 nav_panels.size() - 1 - i)).getSearchCriteria ();
00619                         showResultTree (SeqFeatureData.convertIndexToSequence (
00620                                         genome_choices, index), criteria);
00621                 }
00622         }
00623         
00624         
00633         public void showResultTree (final Genome [] nomes, final String [][] data) {
00634         SwingUtilities.invokeLater(new Runnable(){
00635             public void run(){
00636                 result_pane.displayFeatures (SeqFeatureData.findFeatures (nomes, data));
00637             }
00638         });
00639         }
00640 
00647         public void displayFeature (Feature feat, Genome genome) {
00648                 try {
00649                         adjustZoom(feat);
00650                         goToPosition(SeqFeatureData.centerOfFeature(feat), genome, rrpanel);
00651                         data_model.highlightRange(genome,
00652                                         feat.getLocation().getMin(), feat.getLocation().getMax());
00653                 } catch (Exception e) {
00654                         e.printStackTrace ();
00655                 }               
00656         }
00657 
00662         public void adjustZoom (Feature feat) {
00663                 int length = feat.getLocation().getMax () - feat.getLocation ().getMin();
00664                 long vis_length = ((Genome) genomes.getItemAt(
00665                                 genomes.getItemCount() == 1 ? 0 : 1)).getViewLength ();
00666                 double percent = 0;
00667                 double new_vis = 0;
00668                 int count = 0;
00669                 if (length < vis_length) {
00670                         new_vis = length * 10;
00671                         if (new_vis < vis_length) {
00672                                 percent = ((double) vis_length) / new_vis;
00673                                 percent *= 100;
00674                         }
00675                 }
00676                 else {
00677                         new_vis = length + 1/3*((double) length);
00678                         percent = vis_length/new_vis * 100;
00679                         while (percent < 1) {
00680                                 percent *= 2;
00681                                 count++;
00682                         }
00683                 }
00684                 if (percent != 0) {
00685                         data_model.zoomAndMove ((int) percent, 0);
00686                         while (count > 0) {
00687                                 data_model.zoomAndMove (50, 0);
00688                                 count--;
00689                         }
00690                 }
00691         }
00692         
00700         public static void goToPosition (long position, Genome chosen, RearrangementPanel rrpanel) {
00701                 Object [] panels = rrpanel.newPanels.toArray ();
00702                 for (int i = 0; i < panels.length; i++) {
00703                         RRSequencePanel panel = (RRSequencePanel) ((SeqPanel) 
00704                                         panels [i]).getSequencePanel ();
00705                         if (panel.isForGenome (chosen)) {
00706                                 panel.goTo (position);
00707                                 break;
00708                         }
00709                 }
00710         }
00711         
00718         public void goToPosition (long position, Genome chosen) {
00719                 goToPosition (position, chosen, rrpanel);
00720         }
00721         
00728         public Vector getGenomeKeys () {
00729                 Vector readable = new Vector ();
00730                 Iterator itty = ANNOTATION_KEYS.iterator();
00731                 while (itty.hasNext())
00732                         readable.add(((String) itty.next ()).replace ('_', ' '));
00733                 Collections.sort (readable);
00734                 return readable;
00735         }
00736         
00737         public void dispose () {
00738                 if(parent_component instanceof Frame)
00739                         ((Frame)parent_component).removeWindowListener (adapt);
00740                 else if(parent_component instanceof JComponent)
00741                         ((JComponent)parent_component).removeAncestorListener(ancestListener);
00742                 frame.dispose ();
00743         }
00744         
00745 }

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