2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
26 package org.forester.archaeopteryx;
28 import java.awt.event.KeyEvent;
29 import java.awt.event.KeyListener;
30 import java.math.BigDecimal;
32 import java.text.ParseException;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
38 import javax.swing.JEditorPane;
39 import javax.swing.JOptionPane;
40 import javax.swing.JPanel;
41 import javax.swing.JScrollPane;
42 import javax.swing.JSplitPane;
43 import javax.swing.JTree;
44 import javax.swing.event.TreeSelectionEvent;
45 import javax.swing.event.TreeSelectionListener;
46 import javax.swing.text.Position;
47 import javax.swing.tree.DefaultMutableTreeNode;
48 import javax.swing.tree.TreePath;
49 import javax.swing.tree.TreeSelectionModel;
51 import org.forester.archaeopteryx.tools.ImageLoader;
52 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
53 import org.forester.phylogeny.PhylogenyNode;
54 import org.forester.phylogeny.data.Accession;
55 import org.forester.phylogeny.data.BranchWidth;
56 import org.forester.phylogeny.data.Confidence;
57 import org.forester.phylogeny.data.Date;
58 import org.forester.phylogeny.data.Distribution;
59 import org.forester.phylogeny.data.Event;
60 import org.forester.phylogeny.data.Identifier;
61 import org.forester.phylogeny.data.MultipleUris;
62 import org.forester.phylogeny.data.PhylogenyData;
63 import org.forester.phylogeny.data.PhylogenyDataUtil;
64 import org.forester.phylogeny.data.Point;
65 import org.forester.phylogeny.data.Reference;
66 import org.forester.phylogeny.data.Sequence;
67 import org.forester.phylogeny.data.Taxonomy;
68 import org.forester.phylogeny.data.Uri;
69 import org.forester.util.FailedConditionCheckException;
70 import org.forester.util.ForesterUtil;
72 class NodeEditPanel extends JPanel {
74 private enum PHYLOXML_TAG {
79 TAXONOMY_SCIENTIFIC_NAME,
116 private class TagNumber {
118 final private PHYLOXML_TAG _tag;
119 final private int _number;
121 TagNumber( final PHYLOXML_TAG tag, final int number ) {
127 public String toString() {
128 return getTag() + "_" + getNumber();
135 PHYLOXML_TAG getTag() {
139 private static final long serialVersionUID = 5120159904388100771L;
140 private final JTree _tree;
141 private final JEditorPane _pane;
142 private final PhylogenyNode _my_node;
143 private final TreePanel _tree_panel;
144 private final Map<DefaultMutableTreeNode, TagNumber> _map;
146 public NodeEditPanel( final PhylogenyNode phylogeny_node, final TreePanel tree_panel ) {
147 _map = new HashMap<DefaultMutableTreeNode, TagNumber>();
148 _my_node = phylogeny_node;
149 _tree_panel = tree_panel;
150 String node_name = "";
151 if ( !ForesterUtil.isEmpty( phylogeny_node.getName() ) ) {
152 node_name = phylogeny_node.getName() + " ";
154 final DefaultMutableTreeNode top = new DefaultMutableTreeNode( "Node " + node_name );
155 createNodes( top, phylogeny_node );
156 _tree = new JTree( top );
157 getJTree().setEditable( true );
158 getJTree().setFocusable( true );
159 getJTree().setToggleClickCount( 1 );
160 getJTree().setInvokesStopCellEditing( true );
161 final JScrollPane tree_view = new JScrollPane( getJTree() );
162 _pane = new JEditorPane();
163 _pane.setEditable( true );
164 final JScrollPane data_view = new JScrollPane( _pane );
165 final JSplitPane split_pane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
166 split_pane.setTopComponent( tree_view );
167 // split_pane.setBottomComponent( data_view );
168 data_view.setMinimumSize( AptxConstants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
169 tree_view.setMinimumSize( AptxConstants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
170 // split_pane.setDividerLocation( 400 );
171 split_pane.setPreferredSize( AptxConstants.NODE_PANEL_SIZE );
173 getJTree().getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
174 getJTree().addKeyListener( new KeyListener() {
177 public void keyPressed( final KeyEvent e ) {
182 public void keyReleased( final KeyEvent e ) {
187 public void keyTyped( final KeyEvent e ) {
191 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
192 getJTree().expandRow( i );
194 collapsePath( NodePanel.BASIC );
195 collapsePath( NodePanel.TAXONOMY );
196 collapsePath( NodePanel.SEQUENCE );
197 collapsePath( NodePanel.EVENTS );
198 collapsePath( NodePanel.DATE );
199 collapsePath( NodePanel.DISTRIBUTION );
200 collapsePath( NodePanel.LIT_REFERENCE );
201 getJTree().addTreeSelectionListener( new TreeSelectionListener() {
204 public void valueChanged( final TreeSelectionEvent e ) {
205 final TreePath new_path = e.getNewLeadSelectionPath();
206 final TreePath old_path = e.getOldLeadSelectionPath();
207 if ( new_path != null ) {
208 writeBack( ( DefaultMutableTreeNode ) new_path.getLastPathComponent() );
210 if ( old_path != null ) {
211 writeBack( ( DefaultMutableTreeNode ) old_path.getLastPathComponent() );
213 AptxUtil.lookAtRealBranchLengthsForAptxControlSettings( tree_panel.getPhylogeny(),
214 tree_panel.getControlPanel() );
215 getTreePanel().repaint();
221 private void addBasics( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node, final String name ) {
222 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
224 addSubelementEditable( category, NodePanel.NODE_NAME, phylogeny_node.getName(), PHYLOXML_TAG.NODE_NAME );
226 if ( phylogeny_node.getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) {
227 bl = ForesterUtil.FORMATTER_6.format( phylogeny_node.getDistanceToParent() );
229 addSubelementEditable( category, NodePanel.NODE_BRANCH_LENGTH, bl, PHYLOXML_TAG.NODE_BRANCH_LENGTH );
231 if ( phylogeny_node.getBranchData().isHasConfidences() ) {
232 for( int i = phylogeny_node.getBranchData().getConfidences().size() - 1; i >= 0; i-- ) {
233 if ( phylogeny_node.getBranchData().getConfidences().get( i ).getValue() == Confidence.CONFIDENCE_DEFAULT_VALUE ) {
234 phylogeny_node.getBranchData().getConfidences().remove( i );
237 for( final PhylogenyData conf : phylogeny_node.getBranchData().getConfidences() ) {
238 final Confidence my_conf = ( Confidence ) ( conf );
239 addSubelementEditable( category,
240 NodePanel.CONFIDENCE + " [" + counter + "]",
241 ForesterUtil.FORMATTER_6.format( my_conf.getValue() ),
242 PHYLOXML_TAG.CONFIDENCE_VALUE,
243 NodePanel.CONFIDENCE_TYPE,
245 PHYLOXML_TAG.CONFIDENCE_TYPE,
249 addSubelementEditable( category,
250 NodePanel.CONFIDENCE + " [" + counter + "]",
252 PHYLOXML_TAG.CONFIDENCE_VALUE,
253 NodePanel.CONFIDENCE_TYPE,
255 PHYLOXML_TAG.CONFIDENCE_TYPE,
258 if ( ( phylogeny_node.getBranchData().getBranchWidth() != null )
259 && ( phylogeny_node.getBranchData().getBranchWidth().getValue() != BranchWidth.BRANCH_WIDTH_DEFAULT_VALUE ) ) {
260 bw = ForesterUtil.FORMATTER_3.format( phylogeny_node.getBranchData().getBranchWidth().getValue() );
262 addSubelementEditable( category, NodePanel.NODE_BRANCH_WIDTH, bw, PHYLOXML_TAG.NODE_BRANCH_WIDTH );
265 // private void addAnnotation( final DefaultMutableTreeNode top, final Annotation ann, final String name ) {
266 // DefaultMutableTreeNode category;
267 // category = new DefaultMutableTreeNode( name );
268 // top.add( category );
269 // addSubelementEditable( category, "Reference", ann.getRef() , PHYLOXML_TAG.);
270 // addSubelementEditable( category, "Description", ann.getDesc() , PHYLOXML_TAG.);
271 // addSubelementEditable( category, "Source", ann.getSource(), PHYLOXML_TAG. );
272 // addSubelementEditable( category, "Type", ann.getType(), PHYLOXML_TAG. );
273 // addSubelementEditable( category, "Evidence", ann.getEvidence() , PHYLOXML_TAG.);
274 // if ( ann.getConfidence() != null ) {
275 // addSubelementEditable( category, "Confidence", ann.getConfidence().asText().toString() , PHYLOXML_TAG.);
277 // if ( ann.getProperties() != null ) {
278 // addProperties( category, ann.getProperties(), "Properties", PHYLOXML_TAG. );
281 // private void addAnnotations( final DefaultMutableTreeNode top,
282 // final List<PhylogenyData> annotations,
283 // final DefaultMutableTreeNode category ) {
284 // if ( ( annotations != null ) && ( annotations.size() > 0 ) ) {
285 // category.add( new DefaultMutableTreeNode( "Annotations" ) );
286 // final DefaultMutableTreeNode last = top.getLastLeaf();
288 // for( final PhylogenyData ann : annotations ) {
289 // addAnnotation( last, ( Annotation ) ann, "Annotation " + ( i++ ) );
293 private void addDate( final DefaultMutableTreeNode top, Date date, final String name ) {
294 if ( date == null ) {
297 DefaultMutableTreeNode category;
298 category = new DefaultMutableTreeNode( name );
300 addSubelementEditable( category, NodePanel.DATE_DESCRIPTION, date.getDesc(), PHYLOXML_TAG.DATE_DESCRIPTION );
301 addSubelementEditable( category,
302 NodePanel.DATE_VALUE,
303 String.valueOf( date.getValue() != null ? date.getValue() : "" ),
304 PHYLOXML_TAG.DATE_VALUE );
305 addSubelementEditable( category,
307 String.valueOf( date.getMin() != null ? date.getMin() : "" ),
308 PHYLOXML_TAG.DATE_MIN );
309 addSubelementEditable( category,
311 String.valueOf( date.getMax() != null ? date.getMax() : "" ),
312 PHYLOXML_TAG.DATE_MAX );
313 addSubelementEditable( category, NodePanel.DATE_UNIT, date.getUnit(), PHYLOXML_TAG.DATE_UNIT );
316 private void addDistribution( final DefaultMutableTreeNode top, Distribution dist, final String name ) {
317 if ( dist == null ) {
318 dist = new Distribution( "" );
320 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
323 if ( ( dist.getPoints() != null ) && ( dist.getPoints().size() > 0 ) ) {
324 p0 = dist.getPoints().get( 0 );
329 addSubelementEditable( category, NodePanel.DIST_DESCRIPTION, dist.getDesc(), PHYLOXML_TAG.DIST_DESC );
330 addSubelementEditable( category,
331 NodePanel.DIST_GEODETIC_DATUM,
332 p0.getGeodeticDatum(),
333 PHYLOXML_TAG.DIST_GEODETIC );
334 addSubelementEditable( category,
335 NodePanel.DIST_LATITUDE,
336 String.valueOf( p0.getLatitude() != null ? p0.getLatitude() : "" ),
337 PHYLOXML_TAG.DIST_LAT );
338 addSubelementEditable( category,
339 NodePanel.DIST_LONGITUDE,
340 String.valueOf( p0.getLongitude() != null ? p0.getLongitude() : "" ),
341 PHYLOXML_TAG.DIST_LONG );
342 addSubelementEditable( category,
343 NodePanel.DIST_ALTITUDE,
344 String.valueOf( p0.getAltitude() != null ? p0.getAltitude() : "" ),
345 PHYLOXML_TAG.DIST_ALT );
346 addSubelementEditable( category,
347 NodePanel.DIST_ALT_UNIT,
348 String.valueOf( p0.getAltiudeUnit() != null ? p0.getAltiudeUnit() : "" ),
349 PHYLOXML_TAG.DIST_ALT_UNIT );
352 private void addEvents( final DefaultMutableTreeNode top, Event events, final String name ) {
353 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
354 if ( events == null ) {
355 events = new Event();
358 addSubelementEditable( category,
359 NodePanel.EVENTS_DUPLICATIONS,
360 String.valueOf( events.getNumberOfDuplications() >= 0 ? events.getNumberOfDuplications()
362 PHYLOXML_TAG.EVENTS_DUPLICATIONS );
363 addSubelementEditable( category,
364 NodePanel.EVENTS_SPECIATIONS,
365 String.valueOf( events.getNumberOfSpeciations() >= 0 ? events.getNumberOfSpeciations()
367 PHYLOXML_TAG.EVENTS_SPECIATIONS );
368 addSubelementEditable( category,
369 NodePanel.EVENTS_GENE_LOSSES,
370 String.valueOf( events.getNumberOfGeneLosses() >= 0 ? events.getNumberOfGeneLosses() : 0 ),
371 PHYLOXML_TAG.EVENTS_GENE_LOSSES );
374 private void addMapping( final DefaultMutableTreeNode mtn, final TagNumber tag ) {
375 if ( getMap().containsKey( mtn ) ) {
376 throw new IllegalArgumentException( "key " + mtn + " already present" );
378 if ( getMap().containsValue( tag ) ) {
379 throw new IllegalArgumentException( "value " + tag + " already present" );
381 getMap().put( mtn, tag );
384 private void addReference( final DefaultMutableTreeNode top, Reference ref, final String name ) {
386 ref = new Reference( "" );
388 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
390 addSubelementEditable( category,
391 NodePanel.LIT_REFERENCE_DESC,
392 ref.getDescription(),
393 PHYLOXML_TAG.LIT_REFERENCE_DESC );
394 addSubelementEditable( category, NodePanel.LIT_REFERENCE_DOI, ref.getDoi(), PHYLOXML_TAG.LIT_REFERENCE_DOI );
397 private void addSequence( final DefaultMutableTreeNode top, Sequence seq, final String name ) {
399 seq = new Sequence();
401 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
403 Accession acc = seq.getAccession();
405 acc = new Accession( "", "" );
407 addSubelementEditable( category, NodePanel.SEQ_NAME, seq.getName(), PHYLOXML_TAG.SEQ_NAME );
408 addSubelementEditable( category, NodePanel.SEQ_SYMBOL, seq.getSymbol(), PHYLOXML_TAG.SEQ_SYMBOL );
409 addSubelementEditable( category, NodePanel.SEQ_GENE_NAME, seq.getGeneName(), PHYLOXML_TAG.SEQ_GENE_NAME );
410 addSubelementEditable( category,
411 NodePanel.SEQ_ACCESSION,
413 PHYLOXML_TAG.SEQ_ACC_VALUE,
416 PHYLOXML_TAG.SEQ_ACC_SOURCE );
417 addSubelementEditable( category, NodePanel.SEQ_LOCATION, seq.getLocation(), PHYLOXML_TAG.SEQ_LOCATION );
418 addSubelementEditable( category, NodePanel.SEQ_TYPE, seq.getType(), PHYLOXML_TAG.SEQ_TYPE );
419 addSubelementEditable( category, NodePanel.SEQ_MOL_SEQ, seq.getMolecularSequence(), PHYLOXML_TAG.SEQ_MOL_SEQ );
421 if ( seq.getUris() != null ) {
422 for( final Uri uri : seq.getUris() ) {
424 addSubelementEditable( category, NodePanel.SEQ_URI + " [" + uri_counter + "]", uri.getValue()
425 .toString(), PHYLOXML_TAG.SEQ_URI, uri_counter++ );
429 addSubelementEditable( category,
430 NodePanel.SEQ_URI + " [" + uri_counter + "]",
432 PHYLOXML_TAG.SEQ_URI,
434 // addAnnotations( top, seq.getAnnotations(), category );
437 private void addSubelementEditable( final DefaultMutableTreeNode node,
440 final PHYLOXML_TAG phyloxml_tag ) {
441 addSubelementEditable( node, name, value, phyloxml_tag, 0 );
444 private void addSubelementEditable( final DefaultMutableTreeNode node,
447 final PHYLOXML_TAG phyloxml_tag,
449 String my_value = value;
450 if ( ForesterUtil.isEmpty( my_value ) ) {
453 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
454 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
455 name_node.add( value_node );
456 node.add( name_node );
457 addMapping( name_node, new TagNumber( phyloxml_tag, number ) );
460 private void addSubelementEditable( final DefaultMutableTreeNode node,
463 final PHYLOXML_TAG phyloxml_value_tag,
464 final String source_name,
465 final String source_value,
466 final PHYLOXML_TAG phyloxml_source_tag ) {
467 addSubelementEditable( node, name, value, phyloxml_value_tag, source_name, source_value, phyloxml_source_tag, 0 );
470 private void addSubelementEditable( final DefaultMutableTreeNode node,
473 final PHYLOXML_TAG phyloxml_value_tag,
474 final String source_name,
475 final String source_value,
476 final PHYLOXML_TAG phyloxml_source_tag,
478 String my_value = value;
479 if ( ForesterUtil.isEmpty( my_value ) ) {
482 String my_source_value = source_value;
483 if ( ForesterUtil.isEmpty( my_source_value ) ) {
484 my_source_value = "";
486 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
487 final DefaultMutableTreeNode source_name_node = new DefaultMutableTreeNode( source_name );
488 final DefaultMutableTreeNode source_value_node = new DefaultMutableTreeNode( my_source_value );
489 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
490 name_node.add( source_name_node );
491 source_name_node.add( source_value_node );
492 name_node.add( value_node );
493 node.add( name_node );
494 addMapping( name_node, new TagNumber( phyloxml_value_tag, number ) );
495 addMapping( source_name_node, new TagNumber( phyloxml_source_tag, number ) );
498 private void addTaxonomy( final DefaultMutableTreeNode top, Taxonomy tax, final String name ) {
500 tax = new Taxonomy();
502 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
504 Identifier id = tax.getIdentifier();
506 id = new Identifier();
508 addSubelementEditable( category,
509 NodePanel.TAXONOMY_IDENTIFIER,
511 PHYLOXML_TAG.TAXONOMY_ID_VALUE,
514 PHYLOXML_TAG.TAXONOMY_ID_PROVIDER );
515 addSubelementEditable( category, NodePanel.TAXONOMY_CODE, tax.getTaxonomyCode(), PHYLOXML_TAG.TAXONOMY_CODE );
516 addSubelementEditable( category,
517 NodePanel.TAXONOMY_SCIENTIFIC_NAME,
518 tax.getScientificName(),
519 PHYLOXML_TAG.TAXONOMY_SCIENTIFIC_NAME );
520 addSubelementEditable( category,
521 NodePanel.TAXONOMY_AUTHORITY,
523 PHYLOXML_TAG.TAXONOMY_AUTHORITY );
524 addSubelementEditable( category,
525 NodePanel.TAXONOMY_COMMON_NAME,
527 PHYLOXML_TAG.TAXONOMY_COMMON_NAME );
528 for( int i = tax.getSynonyms().size() - 1; i >= 0; i-- ) {
529 if ( ForesterUtil.isEmpty( tax.getSynonyms().get( i ) ) ) {
530 tax.getSynonyms().remove( i );
534 for( final String syn : tax.getSynonyms() ) {
535 addSubelementEditable( category,
536 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
538 PHYLOXML_TAG.TAXONOMY_SYNONYM,
541 addSubelementEditable( category,
542 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
544 PHYLOXML_TAG.TAXONOMY_SYNONYM,
546 addSubelementEditable( category, NodePanel.TAXONOMY_RANK, tax.getRank(), PHYLOXML_TAG.TAXONOMY_RANK );
548 if ( tax.getUris() != null ) {
549 for( final Uri uri : tax.getUris() ) {
551 addSubelementEditable( category, NodePanel.TAXONOMY_URI + " [" + uri_counter + "]", uri.getValue()
552 .toString(), PHYLOXML_TAG.TAXONOMY_URI, uri_counter++ );
556 addSubelementEditable( category,
557 NodePanel.TAXONOMY_URI + " [" + uri_counter + "]",
559 PHYLOXML_TAG.TAXONOMY_URI,
563 private void addUri( final DefaultMutableTreeNode mtn, final Uri uri, final int number, final MultipleUris mu ) {
565 if ( mu.getUris() == null ) {
566 mu.setUris( new ArrayList<Uri>() );
569 if ( ( uri != null ) && ( mu.getUris() == null ) ) {
570 mu.setUris( new ArrayList<Uri>() );
572 if ( ( uri != null ) && ( mu.getUris().size() == number ) ) {
573 mu.getUris().add( uri );
575 if ( ( mu.getUris() != null ) && ( mu.getUris().size() != number ) ) {
576 mu.getUris().set( number, uri );
578 final ImageLoader il = new ImageLoader( getTreePanel() );
579 new Thread( il ).start();
582 private void collapsePath( final String name ) {
583 final TreePath tp = getJTree().getNextMatch( name, 0, Position.Bias.Forward );
585 getJTree().collapsePath( tp );
589 private void createNodes( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node ) {
590 if ( !phylogeny_node.getNodeData().isHasTaxonomy() ) {
591 phylogeny_node.getNodeData().addTaxonomy( new Taxonomy() );
593 if ( !phylogeny_node.getNodeData().isHasSequence() ) {
594 phylogeny_node.getNodeData().addSequence( new Sequence() );
596 if ( !phylogeny_node.getNodeData().isHasDistribution() ) {
597 phylogeny_node.getNodeData().addDistribution( new Distribution( "" ) );
599 if ( !phylogeny_node.getNodeData().isHasReference() ) {
600 phylogeny_node.getNodeData().addReference( new Reference( "" ) );
602 addBasics( top, phylogeny_node, NodePanel.BASIC );
603 addTaxonomy( top, phylogeny_node.getNodeData().getTaxonomy(), NodePanel.TAXONOMY );
604 addSequence( top, phylogeny_node.getNodeData().getSequence(), NodePanel.SEQUENCE );
605 if ( !phylogeny_node.isExternal() ) {
606 addEvents( top, phylogeny_node.getNodeData().getEvent(), NodePanel.EVENTS );
608 addDate( top, phylogeny_node.getNodeData().getDate(), NodePanel.DATE );
609 addDistribution( top, phylogeny_node.getNodeData().getDistribution(), NodePanel.DISTRIBUTION );
610 addReference( top, phylogeny_node.getNodeData().getReference(), NodePanel.LIT_REFERENCE );
611 // addProperties( top, phylogeny_node.getNodeData().getProperties(), "Properties" );
614 private void formatError( final DefaultMutableTreeNode mtn, final PhyloXmlDataFormatException e ) {
615 JOptionPane.showMessageDialog( this, e.getMessage(), "Format error", JOptionPane.ERROR_MESSAGE );
616 mtn.setUserObject( "" );
617 getJTree().repaint();
620 private JTree getJTree() {
624 private Map<DefaultMutableTreeNode, TagNumber> getMap() {
628 private TagNumber getMapping( final DefaultMutableTreeNode mtn ) {
629 return getMap().get( mtn );
632 private DefaultMutableTreeNode getSelectedTreeNode() {
633 final TreePath selectionPath = getJTree().getSelectionPath();
634 if ( selectionPath != null ) {
635 final Object[] path = selectionPath.getPath();
636 if ( path.length > 0 ) {
637 return ( DefaultMutableTreeNode ) path[ path.length - 1 ]; // Last node
643 private TreePanel getTreePanel() {
647 private void keyEvent( final KeyEvent e ) {
648 if ( e.getKeyCode() == KeyEvent.VK_ENTER ) {
649 writeBack( getSelectedTreeNode() );
653 private List<Point> obtainPoints() {
654 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
655 Distribution d = getMyNode().getNodeData().getDistribution();
656 if ( d.getPoints() == null ) {
657 d = new Distribution( d.getDesc(), new ArrayList<Point>(), d.getPolygons() );
658 getMyNode().getNodeData().setDistribution( d );
660 final List<Point> ps = d.getPoints();
661 if ( ps.isEmpty() ) {
662 ps.add( new Point() );
664 else if ( ps.get( 0 ) == null ) {
665 ps.set( 0, new Point() );
670 private BigDecimal parseBigDecimal( final DefaultMutableTreeNode mtn, final String value ) {
671 if ( ForesterUtil.isEmpty( value ) ) {
672 return new BigDecimal( 0 );
676 i = new BigDecimal( value );
678 catch ( final NumberFormatException e ) {
679 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
680 mtn.setUserObject( "" );
685 private int parsePositiveInt( final DefaultMutableTreeNode mtn, final String value ) {
686 if ( ForesterUtil.isEmpty( value ) ) {
691 i = ForesterUtil.parseInt( value );
693 catch ( final ParseException e ) {
694 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
695 mtn.setUserObject( "" );
698 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
699 mtn.setUserObject( "" );
704 private void writeBack( final DefaultMutableTreeNode mtn ) {
705 if ( !getMap().containsKey( mtn ) ) {
706 final DefaultMutableTreeNode parent = ( DefaultMutableTreeNode ) mtn.getParent();
707 if ( getMap().containsKey( parent ) ) {
708 writeBack( mtn, getMapping( parent ) );
713 private void writeBack( final DefaultMutableTreeNode mtn, final TagNumber tag_number ) {
714 if ( tag_number == null ) {
717 String value = mtn.toString();
718 if ( value == null ) {
721 value = value.replaceAll( "\\s+", " " );
722 value = value.trim();
723 mtn.setUserObject( value );
724 getJTree().repaint();
725 final PHYLOXML_TAG tag = tag_number.getTag();
726 final int number = tag_number.getNumber();
729 getMyNode().setName( value );
731 case NODE_BRANCH_LENGTH:
732 if ( ForesterUtil.isEmpty( value ) ) {
733 getMyNode().setDistanceToParent( PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT );
737 getMyNode().setDistanceToParent( ForesterUtil.parseDouble( value ) );
739 catch ( final ParseException e ) {
740 JOptionPane.showMessageDialog( this,
741 "failed to parse branch length from: " + value,
743 JOptionPane.ERROR_MESSAGE );
744 mtn.setUserObject( "" );
748 case NODE_BRANCH_WIDTH:
749 if ( ForesterUtil.isEmpty( value ) || value.equals( "1" ) ) {
750 if ( getMyNode().getBranchData().getBranchWidth() != null ) {
751 getMyNode().getBranchData().setBranchWidth( new BranchWidth() );
756 final double bw = ForesterUtil.parseDouble( value );
758 getMyNode().getBranchData().setBranchWidth( new BranchWidth( bw ) );
761 catch ( final ParseException e ) {
762 JOptionPane.showMessageDialog( this,
763 "failed to parse branch width from: " + value,
765 JOptionPane.ERROR_MESSAGE );
766 mtn.setUserObject( "" );
770 case CONFIDENCE_VALUE:
771 double confidence = Confidence.CONFIDENCE_DEFAULT_VALUE;
772 if ( !ForesterUtil.isEmpty( value ) ) {
774 confidence = ForesterUtil.parseDouble( value );
776 catch ( final ParseException e ) {
777 JOptionPane.showMessageDialog( this,
778 "failed to parse confidence value from: " + value,
780 JOptionPane.ERROR_MESSAGE );
781 mtn.setUserObject( "" );
785 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
786 throw new FailedConditionCheckException();
788 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
789 if ( confidence >= 0 ) {
790 getMyNode().getBranchData().getConfidences().add( new Confidence( confidence, "unknown" ) );
794 final String type = getMyNode().getBranchData().getConfidences().get( number ).getType();
795 final double sd = getMyNode().getBranchData().getConfidences().get( number ).getStandardDeviation();
796 getMyNode().getBranchData().getConfidences().set( number, new Confidence( confidence, type, sd ) );
799 case CONFIDENCE_TYPE:
800 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
801 throw new FailedConditionCheckException();
803 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
804 if ( !ForesterUtil.isEmpty( value ) ) {
805 getMyNode().getBranchData().getConfidences().add( new Confidence( 0, value ) );
809 final double v = getMyNode().getBranchData().getConfidences().get( number ).getValue();
810 final double sd = getMyNode().getBranchData().getConfidences().get( number ).getStandardDeviation();
811 getMyNode().getBranchData().getConfidences().set( number, new Confidence( v, value, sd ) );
815 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
817 getMyNode().getNodeData().getTaxonomy().setTaxonomyCode( value );
819 catch ( final PhyloXmlDataFormatException e ) {
820 formatError( mtn, e );
824 case TAXONOMY_SCIENTIFIC_NAME:
825 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
826 getMyNode().getNodeData().getTaxonomy().setScientificName( value );
828 case TAXONOMY_COMMON_NAME:
829 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
830 getMyNode().getNodeData().getTaxonomy().setCommonName( value );
833 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
835 getMyNode().getNodeData().getTaxonomy().setRank( value.toLowerCase() );
837 catch ( final PhyloXmlDataFormatException e ) {
838 formatError( mtn, e );
842 case TAXONOMY_AUTHORITY:
843 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
844 getMyNode().getNodeData().getTaxonomy().setAuthority( value );
848 if ( !ForesterUtil.isEmpty( value ) ) {
850 uri = new Uri( new URL( value ).toURI() );
852 catch ( final Exception e ) {
853 JOptionPane.showMessageDialog( this,
854 "failed to parse URL from: " + value,
856 JOptionPane.ERROR_MESSAGE );
857 mtn.setUserObject( "" );
861 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
863 addUri( mtn, uri, number, getMyNode().getNodeData().getTaxonomy() );
866 case TAXONOMY_SYNONYM:
867 if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() < number ) {
868 throw new FailedConditionCheckException();
870 else if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() == number ) {
871 if ( !ForesterUtil.isEmpty( value ) ) {
872 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
873 getMyNode().getNodeData().getTaxonomy().getSynonyms().add( value );
877 getMyNode().getNodeData().getTaxonomy().getSynonyms().set( number, value );
880 case TAXONOMY_ID_VALUE:
881 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
882 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
883 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value ) );
886 final String provider = getMyNode().getNodeData().getTaxonomy().getIdentifier().getProvider();
887 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value, provider ) );
890 case TAXONOMY_ID_PROVIDER:
891 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
892 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
893 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( "", value ) );
896 final String v = getMyNode().getNodeData().getTaxonomy().getIdentifier().getValue();
897 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( v, value ) );
901 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
902 getMyNode().getNodeData().getSequence().setLocation( value );
905 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
906 getMyNode().getNodeData().getSequence().setMolecularSequence( value.replaceAll( "[^a-zA-Z-]", "" ) );
909 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
910 getMyNode().getNodeData().getSequence().setName( value );
913 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
915 getMyNode().getNodeData().getSequence().setSymbol( value );
917 catch ( final PhyloXmlDataFormatException e ) {
918 formatError( mtn, e );
923 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
924 getMyNode().getNodeData().getSequence().setGeneName( value );
927 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
929 getMyNode().getNodeData().getSequence().setType( value.toLowerCase() );
931 catch ( final PhyloXmlDataFormatException e ) {
932 formatError( mtn, e );
937 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
938 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
939 getMyNode().getNodeData().getSequence().setAccession( new Accession( "", value ) );
942 final String v = getMyNode().getNodeData().getSequence().getAccession().getValue();
943 getMyNode().getNodeData().getSequence().setAccession( new Accession( v, value ) );
947 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
948 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
949 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, "" ) );
952 final String source = getMyNode().getNodeData().getSequence().getAccession().getSource();
953 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, source ) );
958 if ( !ForesterUtil.isEmpty( value ) ) {
960 uri = new Uri( new URL( value ).toURI() );
962 catch ( final Exception e ) {
963 JOptionPane.showMessageDialog( this,
964 "failed to parse URL from: " + value,
966 JOptionPane.ERROR_MESSAGE );
967 mtn.setUserObject( "" );
971 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
973 addUri( mtn, uri, number, getMyNode().getNodeData().getSequence() );
976 case LIT_REFERENCE_DESC:
977 if ( !getMyNode().getNodeData().isHasReference() ) {
978 getMyNode().getNodeData().setReference( new Reference( "" ) );
980 getMyNode().getNodeData().getReference().setValue( value );
982 case LIT_REFERENCE_DOI:
983 if ( !getMyNode().getNodeData().isHasReference() ) {
984 getMyNode().getNodeData().setReference( new Reference( "" ) );
987 getMyNode().getNodeData().getReference().setDoi( value );
989 catch ( final PhyloXmlDataFormatException e ) {
990 formatError( mtn, e );
994 case EVENTS_DUPLICATIONS:
995 if ( !getMyNode().getNodeData().isHasEvent() ) {
996 getMyNode().getNodeData().setEvent( new Event() );
998 getMyNode().getNodeData().getEvent().setDuplications( parsePositiveInt( mtn, value ) );
1000 case EVENTS_SPECIATIONS:
1001 if ( !getMyNode().getNodeData().isHasEvent() ) {
1002 getMyNode().getNodeData().setEvent( new Event() );
1004 getMyNode().getNodeData().getEvent().setSpeciations( parsePositiveInt( mtn, value ) );
1006 case EVENTS_GENE_LOSSES:
1007 if ( !getMyNode().getNodeData().isHasEvent() ) {
1008 getMyNode().getNodeData().setEvent( new Event() );
1010 getMyNode().getNodeData().getEvent().setGeneLosses( parsePositiveInt( mtn, value ) );
1012 case DATE_DESCRIPTION:
1013 ForesterUtil.ensurePresenceOfDate( getMyNode() );
1014 getMyNode().getNodeData().getDate().setDesc( value );
1017 ForesterUtil.ensurePresenceOfDate( getMyNode() );
1018 getMyNode().getNodeData().getDate().setMax( parseBigDecimal( mtn, value ) );
1021 ForesterUtil.ensurePresenceOfDate( getMyNode() );
1022 getMyNode().getNodeData().getDate().setMin( parseBigDecimal( mtn, value ) );
1025 ForesterUtil.ensurePresenceOfDate( getMyNode() );
1026 getMyNode().getNodeData().getDate().setUnit( value );
1029 ForesterUtil.ensurePresenceOfDate( getMyNode() );
1030 getMyNode().getNodeData().getDate().setValue( parseBigDecimal( mtn, value ) );
1033 final BigDecimal new_value = parseBigDecimal( mtn, value );
1034 if ( new_value != null ) {
1035 final List<Point> ps = obtainPoints();
1036 final Point p = ps.get( 0 );
1037 final Point p_new = new Point( p.getGeodeticDatum(),
1041 ForesterUtil.isEmpty( p.getAltiudeUnit() ) ? "?"
1042 : p.getAltiudeUnit() );
1048 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
1049 final Distribution d = getMyNode().getNodeData().getDistribution();
1050 getMyNode().getNodeData().setDistribution( new Distribution( value, d.getPoints(), d.getPolygons() ) );
1053 case DIST_GEODETIC: {
1054 if ( !ForesterUtil.isEmpty( value ) ) {
1055 final List<Point> ps = obtainPoints();
1056 final Point p = ps.get( 0 );
1057 final Point p_new = new Point( value,
1061 p.getAltiudeUnit() );
1066 case DIST_ALT_UNIT: {
1067 if ( !ForesterUtil.isEmpty( value ) ) {
1068 final List<Point> ps = obtainPoints();
1069 final Point p = ps.get( 0 );
1070 final Point p_new = new Point( p.getGeodeticDatum(),
1080 final BigDecimal new_value = parseBigDecimal( mtn, value );
1081 if ( new_value != null ) {
1082 final List<Point> ps = obtainPoints();
1083 final Point p = ps.get( 0 );
1084 final Point p_new = new Point( p.getGeodeticDatum(),
1088 p.getAltiudeUnit() );
1094 final BigDecimal new_value = parseBigDecimal( mtn, value );
1095 if ( new_value != null ) {
1096 final List<Point> ps = obtainPoints();
1097 final Point p = ps.get( 0 );
1098 final Point p_new = new Point( p.getGeodeticDatum(),
1102 p.getAltiudeUnit() );
1108 throw new IllegalArgumentException( "unknown: " + tag );
1111 getJTree().repaint();
1112 getTreePanel().setEdited( true );
1113 getTreePanel().repaint();
1116 PhylogenyNode getMyNode() {
1121 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
1122 final TreePath p = getJTree().getPathForRow( i );
1123 writeBack( ( DefaultMutableTreeNode ) p.getLastPathComponent() );