087d3727000ef791834505f4707f9e2dc9d6af1c
[jalview.git] / src / jalview / gui / TreePanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.analysis.AlignmentSorter;
24 import jalview.analysis.NJTree;
25 import jalview.api.analysis.ScoreModelI;
26 import jalview.api.analysis.ViewBasedAnalysisI;
27 import jalview.bin.Cache;
28 import jalview.commands.CommandI;
29 import jalview.commands.OrderCommand;
30 import jalview.datamodel.Alignment;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.AlignmentView;
33 import jalview.datamodel.BinaryNode;
34 import jalview.datamodel.ColumnSelection;
35 import jalview.datamodel.DBRefEntry;
36 import jalview.datamodel.NodeTransformI;
37 import jalview.datamodel.SequenceFeature;
38 import jalview.datamodel.SequenceI;
39 import jalview.datamodel.SequenceNode;
40 import jalview.io.JalviewFileChooser;
41 import jalview.io.JalviewFileView;
42 import jalview.io.NewickFile;
43 import jalview.jbgui.GTreePanel;
44 import jalview.schemes.ResidueProperties;
45 import jalview.util.MessageManager;
46
47 import java.awt.Font;
48 import java.awt.Graphics;
49 import java.awt.event.ActionEvent;
50 import java.awt.event.ActionListener;
51 import java.awt.image.BufferedImage;
52 import java.beans.PropertyChangeEvent;
53 import java.io.FileOutputStream;
54 import java.util.ArrayList;
55 import java.util.List;
56
57 import javax.imageio.ImageIO;
58 import javax.swing.ButtonGroup;
59 import javax.swing.JMenuItem;
60 import javax.swing.JRadioButtonMenuItem;
61
62 import org.jibble.epsgraphics.EpsGraphics2D;
63
64 /**
65  * DOCUMENT ME!
66  * 
67  * @author $author$
68  * @version $Revision$
69  */
70 public class TreePanel extends GTreePanel
71 {
72   String type;
73
74   String pwtype;
75
76   TreeCanvas treeCanvas;
77
78   NJTree tree;
79
80   AlignViewport av;
81
82   /**
83    * Creates a new TreePanel object.
84    * 
85    * @param av
86    *          DOCUMENT ME!
87    * @param seqVector
88    *          DOCUMENT ME!
89    * @param type
90    *          DOCUMENT ME!
91    * @param pwtype
92    *          DOCUMENT ME!
93    * @param s
94    *          DOCUMENT ME!
95    * @param e
96    *          DOCUMENT ME!
97    */
98   public TreePanel(AlignmentPanel ap, String type, String pwtype)
99   {
100     super();
101     initTreePanel(ap, type, pwtype, null, null);
102
103     // We know this tree has distances. JBPNote TODO: prolly should add this as
104     // a userdefined default
105     // showDistances(true);
106   }
107
108   /**
109    * Creates a new TreePanel object.
110    * 
111    * @param av
112    *          DOCUMENT ME!
113    * @param seqVector
114    *          DOCUMENT ME!
115    * @param newtree
116    *          DOCUMENT ME!
117    * @param type
118    *          DOCUMENT ME!
119    * @param pwtype
120    *          DOCUMENT ME!
121    */
122   public TreePanel(AlignmentPanel ap, String type, String pwtype,
123           NewickFile newtree)
124   {
125     super();
126     initTreePanel(ap, type, pwtype, newtree, null);
127   }
128
129   public TreePanel(AlignmentPanel av, String type, String pwtype,
130           NewickFile newtree, AlignmentView inputData)
131   {
132     super();
133     initTreePanel(av, type, pwtype, newtree, inputData);
134   }
135
136   public AlignmentI getAlignment()
137   {
138     return treeCanvas.av.getAlignment();
139   }
140
141   public AlignViewport getViewPort()
142   {
143     return treeCanvas.av;
144   }
145
146   void initTreePanel(AlignmentPanel ap, String type, String pwtype,
147           NewickFile newTree, AlignmentView inputData)
148   {
149
150     av = ap.av;
151     this.type = type;
152     this.pwtype = pwtype;
153
154     treeCanvas = new TreeCanvas(this, ap, scrollPane);
155     scrollPane.setViewportView(treeCanvas);
156
157     PaintRefresher.Register(this, ap.av.getSequenceSetId());
158
159     buildAssociatedViewMenu();
160
161     av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
162     {
163       public void propertyChange(PropertyChangeEvent evt)
164       {
165         if (evt.getPropertyName().equals("alignment"))
166         {
167           if (tree == null)
168           {
169             System.out.println("tree is null");
170             // TODO: deal with case when a change event is received whilst a
171             // tree is still being calculated - should save reference for
172             // processing message later.
173             return;
174           }
175           if (evt.getNewValue() == null)
176           {
177             System.out
178                     .println("new alignment sequences vector value is null");
179           }
180
181           tree.UpdatePlaceHolders((List<SequenceI>) evt.getNewValue());
182           treeCanvas.nameHash.clear(); // reset the mapping between canvas
183           // rectangles and leafnodes
184           repaint();
185         }
186       }
187     });
188
189     TreeLoader tl = new TreeLoader(newTree);
190     if (inputData != null)
191     {
192       tl.odata = inputData;
193     }
194     tl.start();
195
196   }
197
198   public void viewMenu_menuSelected()
199   {
200     buildAssociatedViewMenu();
201   }
202
203   void buildAssociatedViewMenu()
204   {
205     AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(av
206             .getSequenceSetId());
207     if (aps.length == 1 && treeCanvas.ap == aps[0])
208     {
209       associateLeavesMenu.setVisible(false);
210       return;
211     }
212
213     associateLeavesMenu.setVisible(true);
214
215     if ((viewMenu.getItem(viewMenu.getItemCount() - 2) instanceof JMenuItem))
216     {
217       viewMenu.insertSeparator(viewMenu.getItemCount() - 1);
218     }
219
220     associateLeavesMenu.removeAll();
221
222     JRadioButtonMenuItem item;
223     ButtonGroup buttonGroup = new ButtonGroup();
224     int i, iSize = aps.length;
225     final TreePanel thisTreePanel = this;
226     for (i = 0; i < iSize; i++)
227     {
228       final AlignmentPanel ap = aps[i];
229       item = new JRadioButtonMenuItem(ap.av.viewName, ap == treeCanvas.ap);
230       buttonGroup.add(item);
231       item.addActionListener(new ActionListener()
232       {
233         public void actionPerformed(ActionEvent evt)
234         {
235           treeCanvas.applyToAllViews = false;
236           treeCanvas.ap = ap;
237           treeCanvas.av = ap.av;
238           PaintRefresher.Register(thisTreePanel, ap.av.getSequenceSetId());
239         }
240       });
241
242       associateLeavesMenu.add(item);
243     }
244
245     final JRadioButtonMenuItem itemf = new JRadioButtonMenuItem("All Views");
246     buttonGroup.add(itemf);
247     itemf.setSelected(treeCanvas.applyToAllViews);
248     itemf.addActionListener(new ActionListener()
249     {
250       public void actionPerformed(ActionEvent evt)
251       {
252         treeCanvas.applyToAllViews = itemf.isSelected();
253       }
254     });
255     associateLeavesMenu.add(itemf);
256
257   }
258
259   class TreeLoader extends Thread
260   {
261     NewickFile newtree;
262
263     jalview.datamodel.AlignmentView odata = null;
264
265     public TreeLoader(NewickFile newtree)
266     {
267       this.newtree = newtree;
268       if (newtree != null)
269       {
270         // Must be outside run(), as Jalview2XML tries to
271         // update distance/bootstrap visibility at the same time
272         showBootstrap(newtree.HasBootstrap());
273         showDistances(newtree.HasDistances());
274       }
275     }
276
277     public void run()
278     {
279
280       if (newtree != null)
281       {
282         if (odata == null)
283         {
284           tree = new NJTree(av.getAlignment().getSequencesArray(), newtree);
285         }
286         else
287         {
288           tree = new NJTree(av.getAlignment().getSequencesArray(), odata,
289                   newtree);
290         }
291         if (!tree.hasOriginalSequenceData())
292         {
293           allowOriginalSeqData(false);
294         }
295       }
296       else
297       {
298         int start, end;
299         SequenceI[] seqs;
300         boolean selview = av.getSelectionGroup() != null
301                 && av.getSelectionGroup().getSize() > 1;
302         AlignmentView seqStrings = av.getAlignmentView(selview);
303         if (!selview)
304         {
305           start = 0;
306           end = av.getAlignment().getWidth();
307           seqs = av.getAlignment().getSequencesArray();
308         }
309         else
310         {
311           start = av.getSelectionGroup().getStartRes();
312           end = av.getSelectionGroup().getEndRes() + 1;
313           seqs = av.getSelectionGroup().getSequencesInOrder(
314                   av.getAlignment());
315         }
316         ScoreModelI sm = ResidueProperties.getScoreModel(pwtype);
317         if (sm instanceof ViewBasedAnalysisI)
318         {
319           try
320           {
321             sm = sm.getClass().newInstance();
322             ((ViewBasedAnalysisI) sm)
323                     .configureFromAlignmentView(treeCanvas.ap);
324           } catch (Exception q)
325           {
326             Cache.log.error("Couldn't create a scoremodel instance for "
327                     + sm.getName());
328           }
329           tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
330         }
331         else
332         {
333           tree = new NJTree(seqs, seqStrings, type, pwtype, null, start,
334                   end);
335         }
336         showDistances(true);
337       }
338
339       tree.reCount(tree.getTopNode());
340       tree.findHeight(tree.getTopNode());
341       treeCanvas.setTree(tree);
342       treeCanvas.repaint();
343       av.setCurrentTree(tree);
344       if (av.getSortByTree())
345       {
346         sortByTree_actionPerformed(null);
347       }
348     }
349   }
350
351   public void showDistances(boolean b)
352   {
353     treeCanvas.setShowDistances(b);
354     distanceMenu.setSelected(b);
355   }
356
357   public void showBootstrap(boolean b)
358   {
359     treeCanvas.setShowBootstrap(b);
360     bootstrapMenu.setSelected(b);
361   }
362
363   public void showPlaceholders(boolean b)
364   {
365     placeholdersMenu.setState(b);
366     treeCanvas.setMarkPlaceholders(b);
367   }
368
369   private void allowOriginalSeqData(boolean b)
370   {
371     originalSeqData.setVisible(b);
372   }
373
374   /**
375    * DOCUMENT ME!
376    * 
377    * @return DOCUMENT ME!
378    */
379   public NJTree getTree()
380   {
381     return tree;
382   }
383
384   /**
385    * DOCUMENT ME!
386    * 
387    * @param e
388    *          DOCUMENT ME!
389    */
390   public void textbox_actionPerformed(ActionEvent e)
391   {
392     CutAndPasteTransfer cap = new CutAndPasteTransfer();
393
394     StringBuffer buffer = new StringBuffer();
395
396     if (type.equals("AV"))
397     {
398       buffer.append("Average distance tree using ");
399     }
400     else
401     {
402       buffer.append("Neighbour joining tree using ");
403     }
404
405     if (pwtype.equals("BL"))
406     {
407       buffer.append("BLOSUM62");
408     }
409     else
410     {
411       buffer.append("PID");
412     }
413
414     jalview.io.NewickFile fout = new jalview.io.NewickFile(
415             tree.getTopNode());
416     try
417     {
418       cap.setText(fout.print(tree.isHasBootstrap(), tree.isHasDistances(),
419               tree.isHasRootDistance()));
420       Desktop.addInternalFrame(cap, buffer.toString(), 500, 100);
421     } catch (OutOfMemoryError oom)
422     {
423       new OOMWarning("generating newick tree file", oom);
424       cap.dispose();
425     }
426
427   }
428
429   /**
430    * DOCUMENT ME!
431    * 
432    * @param e
433    *          DOCUMENT ME!
434    */
435   public void saveAsNewick_actionPerformed(ActionEvent e)
436   {
437     JalviewFileChooser chooser = new JalviewFileChooser(
438             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
439     chooser.setFileView(new JalviewFileView());
440     chooser.setDialogTitle(MessageManager.getString("label.save_tree_as_newick"));
441     chooser.setToolTipText(MessageManager.getString("action.save"));
442
443     int value = chooser.showSaveDialog(null);
444
445     if (value == JalviewFileChooser.APPROVE_OPTION)
446     {
447       String choice = chooser.getSelectedFile().getPath();
448       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
449               .getSelectedFile().getParent());
450
451       try
452       {
453         jalview.io.NewickFile fout = new jalview.io.NewickFile(
454                 tree.getTopNode());
455         String output = fout.print(tree.isHasBootstrap(),
456                 tree.isHasDistances(), tree.isHasRootDistance());
457         java.io.PrintWriter out = new java.io.PrintWriter(
458                 new java.io.FileWriter(choice));
459         out.println(output);
460         out.close();
461       } catch (Exception ex)
462       {
463         ex.printStackTrace();
464       }
465     }
466   }
467
468   /**
469    * DOCUMENT ME!
470    * 
471    * @param e
472    *          DOCUMENT ME!
473    */
474   public void printMenu_actionPerformed(ActionEvent e)
475   {
476     // Putting in a thread avoids Swing painting problems
477     treeCanvas.startPrinting();
478   }
479
480   public void originalSeqData_actionPerformed(ActionEvent e)
481   {
482     if (!tree.hasOriginalSequenceData())
483     {
484       jalview.bin.Cache.log
485               .info("Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
486       return;
487     }
488     // decide if av alignment is sufficiently different to original data to
489     // warrant a new window to be created
490     // create new alignmnt window with hidden regions (unhiding hidden regions
491     // yields unaligned seqs)
492     // or create a selection box around columns in alignment view
493     // test Alignment(SeqCigar[])
494     char gc = '-';
495     try
496     {
497       // we try to get the associated view's gap character
498       // but this may fail if the view was closed...
499       gc = av.getGapCharacter();
500
501     } catch (Exception ex)
502     {
503     }
504     ;
505     Object[] alAndColsel = tree.seqData.getAlignmentAndColumnSelection(gc);
506
507     if (alAndColsel != null && alAndColsel[0] != null)
508     {
509       // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);
510
511       Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
512       Alignment dataset = (av != null && av.getAlignment() != null) ? av
513               .getAlignment().getDataset() : null;
514       if (dataset != null)
515       {
516         al.setDataset(dataset);
517       }
518
519       if (true)
520       {
521         // make a new frame!
522         AlignFrame af = new AlignFrame(al,
523                 (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
524                 AlignFrame.DEFAULT_HEIGHT);
525
526         // >>>This is a fix for the moment, until a better solution is
527         // found!!<<<
528         // af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());
529
530         // af.addSortByOrderMenuItem(ServiceName + " Ordering",
531         // msaorder);
532
533         Desktop.addInternalFrame(af, MessageManager.formatMessage(
534                 "label.original_data_for_params", new String[]
535                 { this.title }), AlignFrame.DEFAULT_WIDTH,
536                 AlignFrame.DEFAULT_HEIGHT);
537       }
538     }
539   }
540
541   /**
542    * DOCUMENT ME!
543    * 
544    * @param e
545    *          DOCUMENT ME!
546    */
547   public void fitToWindow_actionPerformed(ActionEvent e)
548   {
549     treeCanvas.fitToWindow = fitToWindow.isSelected();
550     repaint();
551   }
552
553   /**
554    * sort the associated alignment view by the current tree.
555    * 
556    * @param e
557    */
558   public void sortByTree_actionPerformed(ActionEvent e)
559   {
560
561     if (treeCanvas.applyToAllViews)
562     {
563       final ArrayList<CommandI> commands = new ArrayList<CommandI>();
564       for (AlignmentPanel ap : PaintRefresher.getAssociatedPanels(av
565               .getSequenceSetId()))
566       {
567         commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
568       }
569       av.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
570       {
571
572         @Override
573         public void undoCommand(AlignmentI[] views)
574         {
575           for (CommandI tsort : commands)
576           {
577             tsort.undoCommand(views);
578           }
579         }
580
581         @Override
582         public int getSize()
583         {
584           return commands.size();
585         }
586
587         @Override
588         public String getDescription()
589         {
590           return "Tree Sort (many views)";
591         }
592
593         @Override
594         public void doCommand(AlignmentI[] views)
595         {
596
597           for (CommandI tsort : commands)
598           {
599             tsort.doCommand(views);
600           }
601         }
602       });
603       for (AlignmentPanel ap : PaintRefresher.getAssociatedPanels(av
604               .getSequenceSetId()))
605       {
606         // ensure all the alignFrames refresh their GI after adding an undo item
607         ap.alignFrame.updateEditMenuBar();
608       }
609     }
610     else
611     {
612       treeCanvas.ap.alignFrame
613               .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
614     }
615
616   }
617
618   public CommandI sortAlignmentIn(AlignmentPanel ap)
619   {
620     AlignViewport av = ap.av;
621     SequenceI[] oldOrder = av.getAlignment().getSequencesArray();
622     AlignmentSorter.sortByTree(av.getAlignment(), tree);
623     CommandI undo;
624     undo = new OrderCommand("Tree Sort", oldOrder, av.getAlignment());
625
626     ap.paintAlignment(true);
627     return undo;
628   }
629
630   /**
631    * DOCUMENT ME!
632    * 
633    * @param e
634    *          DOCUMENT ME!
635    */
636   public void font_actionPerformed(ActionEvent e)
637   {
638     if (treeCanvas == null)
639     {
640       return;
641     }
642
643     new FontChooser(this);
644   }
645
646   public Font getTreeFont()
647   {
648     return treeCanvas.font;
649   }
650
651   public void setTreeFont(Font font)
652   {
653     if (treeCanvas != null)
654     {
655       treeCanvas.setFont(font);
656     }
657   }
658
659   /**
660    * DOCUMENT ME!
661    * 
662    * @param e
663    *          DOCUMENT ME!
664    */
665   public void distanceMenu_actionPerformed(ActionEvent e)
666   {
667     treeCanvas.setShowDistances(distanceMenu.isSelected());
668   }
669
670   /**
671    * DOCUMENT ME!
672    * 
673    * @param e
674    *          DOCUMENT ME!
675    */
676   public void bootstrapMenu_actionPerformed(ActionEvent e)
677   {
678     treeCanvas.setShowBootstrap(bootstrapMenu.isSelected());
679   }
680
681   /**
682    * DOCUMENT ME!
683    * 
684    * @param e
685    *          DOCUMENT ME!
686    */
687   public void placeholdersMenu_actionPerformed(ActionEvent e)
688   {
689     treeCanvas.setMarkPlaceholders(placeholdersMenu.isSelected());
690   }
691
692   /**
693    * DOCUMENT ME!
694    * 
695    * @param e
696    *          DOCUMENT ME!
697    */
698   public void epsTree_actionPerformed(ActionEvent e)
699   {
700     boolean accurateText = true;
701
702     String renderStyle = jalview.bin.Cache.getDefault("EPS_RENDERING",
703             "Prompt each time");
704
705     // If we need to prompt, and if the GUI is visible then
706     // Prompt for EPS rendering style
707     if (renderStyle.equalsIgnoreCase("Prompt each time")
708             && !(System.getProperty("java.awt.headless") != null && System
709                     .getProperty("java.awt.headless").equals("true")))
710     {
711       EPSOptions eps = new EPSOptions();
712       renderStyle = eps.getValue();
713
714       if (renderStyle == null || eps.cancelled)
715       {
716         return;
717       }
718
719     }
720
721     if (renderStyle.equalsIgnoreCase("text"))
722     {
723       accurateText = false;
724     }
725
726     int width = treeCanvas.getWidth();
727     int height = treeCanvas.getHeight();
728
729     try
730     {
731       jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
732               jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
733               { "eps" }, new String[]
734               { "Encapsulated Postscript" }, "Encapsulated Postscript");
735       chooser.setFileView(new jalview.io.JalviewFileView());
736       chooser.setDialogTitle(MessageManager.getString("label.create_eps_from_tree"));
737       chooser.setToolTipText(MessageManager.getString("action.save"));
738
739       int value = chooser.showSaveDialog(this);
740
741       if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)
742       {
743         return;
744       }
745
746       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
747               .getSelectedFile().getParent());
748
749       FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());
750       EpsGraphics2D pg = new EpsGraphics2D("Tree", out, 0, 0, width, height);
751
752       pg.setAccurateTextMode(accurateText);
753
754       treeCanvas.draw(pg, width, height);
755
756       pg.flush();
757       pg.close();
758     } catch (Exception ex)
759     {
760       ex.printStackTrace();
761     }
762   }
763
764   /**
765    * DOCUMENT ME!
766    * 
767    * @param e
768    *          DOCUMENT ME!
769    */
770   public void pngTree_actionPerformed(ActionEvent e)
771   {
772     int width = treeCanvas.getWidth();
773     int height = treeCanvas.getHeight();
774
775     try
776     {
777       jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
778               jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
779               { "png" }, new String[]
780               { "Portable network graphics" }, "Portable network graphics");
781
782       chooser.setFileView(new jalview.io.JalviewFileView());
783       chooser.setDialogTitle(MessageManager.getString("label.create_png_from_tree"));
784       chooser.setToolTipText(MessageManager.getString("action.save"));
785
786       int value = chooser.showSaveDialog(this);
787
788       if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)
789       {
790         return;
791       }
792
793       jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
794               .getSelectedFile().getParent());
795
796       FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());
797
798       BufferedImage bi = new BufferedImage(width, height,
799               BufferedImage.TYPE_INT_RGB);
800       Graphics png = bi.getGraphics();
801
802       treeCanvas.draw(png, width, height);
803
804       ImageIO.write(bi, "png", out);
805       out.close();
806     } catch (Exception ex)
807     {
808       ex.printStackTrace();
809     }
810   }
811
812   /**
813    * change node labels to the annotation referred to by labelClass TODO:
814    * promote to a datamodel modification that can be undone TODO: make argument
815    * one case of a generic transformation function ie { undoStep = apply(Tree,
816    * TransformFunction)};
817    * 
818    * @param labelClass
819    */
820   public void changeNames(final String labelClass)
821   {
822     tree.applyToNodes(new NodeTransformI()
823     {
824
825       public void transform(BinaryNode node)
826       {
827         if (node instanceof SequenceNode
828                 && !((SequenceNode) node).isPlaceholder()
829                 && !((SequenceNode) node).isDummy())
830         {
831           String newname = null;
832           SequenceI sq = (SequenceI) ((SequenceNode) node).element();
833           if (sq != null)
834           {
835             // search dbrefs, features and annotation
836             DBRefEntry[] refs = jalview.util.DBRefUtils.selectRefs(
837                     sq.getDBRef(), new String[]
838                     { labelClass.toUpperCase() });
839             if (refs != null)
840             {
841               for (int i = 0; i < refs.length; i++)
842               {
843                 if (newname == null)
844                 {
845                   newname = new String(refs[i].getAccessionId());
846                 }
847                 else
848                 {
849                   newname = newname + "; " + refs[i].getAccessionId();
850                 }
851               }
852             }
853             if (newname == null)
854             {
855               SequenceFeature sf[] = sq.getSequenceFeatures();
856               for (int i = 0; sf != null && i < sf.length; i++)
857               {
858                 if (sf[i].getType().equals(labelClass))
859                 {
860                   if (newname == null)
861                   {
862                     newname = new String(sf[i].getDescription());
863                   }
864                   else
865                   {
866                     newname = newname + "; " + sf[i].getDescription();
867                   }
868                 }
869               }
870             }
871           }
872           if (newname != null)
873           {
874             String oldname = ((SequenceNode) node).getName();
875             // TODO : save in the undo object for this modification.
876             ((SequenceNode) node).setName(newname);
877           }
878         }
879       }
880     });
881   }
882 }