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: www.phylosoft.org/
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.Point;
64 import org.forester.phylogeny.data.Reference;
65 import org.forester.phylogeny.data.Sequence;
66 import org.forester.phylogeny.data.Taxonomy;
67 import org.forester.phylogeny.data.Uri;
68 import org.forester.util.FailedConditionCheckException;
69 import org.forester.util.ForesterUtil;
71 class NodeEditPanel extends JPanel {
73 private static final long serialVersionUID = 5120159904388100771L;
74 private final JTree _tree;
75 private final JEditorPane _pane;
76 private final PhylogenyNode _my_node;
77 private final TreePanel _tree_panel;
78 private final Map<DefaultMutableTreeNode, TagNumber> _map;
80 public NodeEditPanel( final PhylogenyNode phylogeny_node, final TreePanel tree_panel ) {
81 _map = new HashMap<DefaultMutableTreeNode, TagNumber>();
82 _my_node = phylogeny_node;
83 _tree_panel = tree_panel;
84 String node_name = "";
85 if ( !ForesterUtil.isEmpty( phylogeny_node.getName() ) ) {
86 node_name = phylogeny_node.getName() + " ";
88 final DefaultMutableTreeNode top = new DefaultMutableTreeNode( "Node " + node_name );
89 createNodes( top, phylogeny_node );
90 _tree = new JTree( top );
91 getJTree().setEditable( true );
92 getJTree().setFocusable( true );
93 getJTree().setToggleClickCount( 1 );
94 getJTree().setInvokesStopCellEditing( true );
95 final JScrollPane tree_view = new JScrollPane( getJTree() );
96 _pane = new JEditorPane();
97 _pane.setEditable( true );
98 final JScrollPane data_view = new JScrollPane( _pane );
99 final JSplitPane split_pane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
100 split_pane.setTopComponent( tree_view );
101 // split_pane.setBottomComponent( data_view );
102 data_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
103 tree_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
104 // split_pane.setDividerLocation( 400 );
105 split_pane.setPreferredSize( Constants.NODE_PANEL_SIZE );
107 getJTree().getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
108 getJTree().addKeyListener( new KeyListener() {
111 public void keyPressed( final KeyEvent e ) {
116 public void keyReleased( final KeyEvent e ) {
121 public void keyTyped( final KeyEvent e ) {
125 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
126 getJTree().expandRow( i );
128 collapsePath( NodePanel.BASIC );
129 collapsePath( NodePanel.TAXONOMY );
130 collapsePath( NodePanel.SEQUENCE );
131 collapsePath( NodePanel.EVENTS );
132 collapsePath( NodePanel.DATE );
133 collapsePath( NodePanel.DISTRIBUTION );
134 collapsePath( NodePanel.LIT_REFERENCE );
135 getJTree().addTreeSelectionListener( new TreeSelectionListener() {
138 public void valueChanged( final TreeSelectionEvent e ) {
139 final TreePath new_path = e.getNewLeadSelectionPath();
140 final TreePath old_path = e.getOldLeadSelectionPath();
141 if ( new_path != null ) {
142 writeBack( ( DefaultMutableTreeNode ) new_path.getLastPathComponent() );
144 if ( old_path != null ) {
145 writeBack( ( DefaultMutableTreeNode ) old_path.getLastPathComponent() );
151 private void addBasics( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node, final String name ) {
152 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
154 addSubelementEditable( category, NodePanel.NODE_NAME, phylogeny_node.getName(), PHYLOXML_TAG.NODE_NAME );
156 if ( phylogeny_node.getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) {
157 bl = ForesterUtil.FORMATTER_6.format( phylogeny_node.getDistanceToParent() );
159 addSubelementEditable( category, NodePanel.NODE_BRANCH_LENGTH, bl, PHYLOXML_TAG.NODE_BRANCH_LENGTH );
161 if ( phylogeny_node.getBranchData().isHasConfidences() ) {
162 for( int i = phylogeny_node.getBranchData().getConfidences().size() - 1; i >= 0; i-- ) {
163 if ( phylogeny_node.getBranchData().getConfidences().get( i ).getValue() == Confidence.CONFIDENCE_DEFAULT_VALUE ) {
164 phylogeny_node.getBranchData().getConfidences().remove( i );
167 for( final PhylogenyData conf : phylogeny_node.getBranchData().getConfidences() ) {
168 final Confidence my_conf = ( Confidence ) ( conf );
169 addSubelementEditable( category,
170 NodePanel.CONFIDENCE + " [" + counter + "]",
171 ForesterUtil.FORMATTER_6.format( my_conf.getValue() ),
172 PHYLOXML_TAG.CONFIDENCE_VALUE,
173 NodePanel.CONFIDENCE_TYPE,
175 PHYLOXML_TAG.CONFIDENCE_TYPE,
179 addSubelementEditable( category,
180 NodePanel.CONFIDENCE + " [" + counter + "]",
182 PHYLOXML_TAG.CONFIDENCE_VALUE,
183 NodePanel.CONFIDENCE_TYPE,
185 PHYLOXML_TAG.CONFIDENCE_TYPE,
188 if ( phylogeny_node.getBranchData().getBranchWidth() != null
189 && phylogeny_node.getBranchData().getBranchWidth().getValue() != BranchWidth.BRANCH_WIDTH_DEFAULT_VALUE
192 bw = ForesterUtil.FORMATTER_3.format( phylogeny_node.getBranchData().getBranchWidth().getValue() );
194 addSubelementEditable( category, NodePanel.NODE_BRANCH_WIDTH, bw, PHYLOXML_TAG.NODE_BRANCH_WIDTH );
198 // private void addAnnotation( final DefaultMutableTreeNode top, final Annotation ann, final String name ) {
199 // DefaultMutableTreeNode category;
200 // category = new DefaultMutableTreeNode( name );
201 // top.add( category );
202 // addSubelementEditable( category, "Reference", ann.getRef() , PHYLOXML_TAG.);
203 // addSubelementEditable( category, "Description", ann.getDesc() , PHYLOXML_TAG.);
204 // addSubelementEditable( category, "Source", ann.getSource(), PHYLOXML_TAG. );
205 // addSubelementEditable( category, "Type", ann.getType(), PHYLOXML_TAG. );
206 // addSubelementEditable( category, "Evidence", ann.getEvidence() , PHYLOXML_TAG.);
207 // if ( ann.getConfidence() != null ) {
208 // addSubelementEditable( category, "Confidence", ann.getConfidence().asText().toString() , PHYLOXML_TAG.);
210 // if ( ann.getProperties() != null ) {
211 // addProperties( category, ann.getProperties(), "Properties", PHYLOXML_TAG. );
214 // private void addAnnotations( final DefaultMutableTreeNode top,
215 // final List<PhylogenyData> annotations,
216 // final DefaultMutableTreeNode category ) {
217 // if ( ( annotations != null ) && ( annotations.size() > 0 ) ) {
218 // category.add( new DefaultMutableTreeNode( "Annotations" ) );
219 // final DefaultMutableTreeNode last = top.getLastLeaf();
221 // for( final PhylogenyData ann : annotations ) {
222 // addAnnotation( last, ( Annotation ) ann, "Annotation " + ( i++ ) );
226 private void addDate( final DefaultMutableTreeNode top, Date date, final String name ) {
227 if ( date == null ) {
230 DefaultMutableTreeNode category;
231 category = new DefaultMutableTreeNode( name );
233 addSubelementEditable( category, NodePanel.DATE_DESCRIPTION, date.getDesc(), PHYLOXML_TAG.DATE_DESCRIPTION );
234 addSubelementEditable( category,
235 NodePanel.DATE_VALUE,
236 String.valueOf( date.getValue() != null ? date.getValue() : "" ),
237 PHYLOXML_TAG.DATE_VALUE );
238 addSubelementEditable( category,
240 String.valueOf( date.getMin() != null ? date.getMin() : "" ),
241 PHYLOXML_TAG.DATE_MIN );
242 addSubelementEditable( category,
244 String.valueOf( date.getMax() != null ? date.getMax() : "" ),
245 PHYLOXML_TAG.DATE_MAX );
246 addSubelementEditable( category, NodePanel.DATE_UNIT, date.getUnit(), PHYLOXML_TAG.DATE_UNIT );
249 private void addDistribution( final DefaultMutableTreeNode top, Distribution dist, final String name ) {
250 if ( dist == null ) {
251 dist = new Distribution( "" );
253 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
256 if ( ( dist.getPoints() != null ) && ( dist.getPoints().size() > 0 ) ) {
257 p0 = dist.getPoints().get( 0 );
262 addSubelementEditable( category, NodePanel.DIST_DESCRIPTION, dist.getDesc(), PHYLOXML_TAG.DIST_DESC );
263 addSubelementEditable( category,
264 NodePanel.DIST_GEODETIC_DATUM,
265 p0.getGeodeticDatum(),
266 PHYLOXML_TAG.DIST_GEODETIC );
267 addSubelementEditable( category,
268 NodePanel.DIST_LATITUDE,
269 String.valueOf( p0.getLatitude() != null ? p0.getLatitude() : "" ),
270 PHYLOXML_TAG.DIST_LAT );
271 addSubelementEditable( category,
272 NodePanel.DIST_LONGITUDE,
273 String.valueOf( p0.getLongitude() != null ? p0.getLongitude() : "" ),
274 PHYLOXML_TAG.DIST_LONG );
275 addSubelementEditable( category,
276 NodePanel.DIST_ALTITUDE,
277 String.valueOf( p0.getAltitude() != null ? p0.getAltitude() : "" ),
278 PHYLOXML_TAG.DIST_ALT );
279 addSubelementEditable( category,
280 NodePanel.DIST_ALT_UNIT,
281 String.valueOf( p0.getAltiudeUnit() != null ? p0.getAltiudeUnit() : "" ),
282 PHYLOXML_TAG.DIST_ALT_UNIT );
285 private void addEvents( final DefaultMutableTreeNode top, Event events, final String name ) {
286 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
287 if ( events == null ) {
288 events = new Event();
291 addSubelementEditable( category,
292 NodePanel.EVENTS_DUPLICATIONS,
293 String.valueOf( events.getNumberOfDuplications() >= 0 ? events.getNumberOfDuplications()
295 PHYLOXML_TAG.EVENTS_DUPLICATIONS );
296 addSubelementEditable( category,
297 NodePanel.EVENTS_SPECIATIONS,
298 String.valueOf( events.getNumberOfSpeciations() >= 0 ? events.getNumberOfSpeciations()
300 PHYLOXML_TAG.EVENTS_SPECIATIONS );
301 addSubelementEditable( category,
302 NodePanel.EVENTS_GENE_LOSSES,
303 String.valueOf( events.getNumberOfGeneLosses() >= 0 ? events.getNumberOfGeneLosses() : 0 ),
304 PHYLOXML_TAG.EVENTS_GENE_LOSSES );
307 private void addMapping( final DefaultMutableTreeNode mtn, final TagNumber tag ) {
308 if ( getMap().containsKey( mtn ) ) {
309 throw new IllegalArgumentException( "key " + mtn + " already present" );
311 if ( getMap().containsValue( tag ) ) {
312 throw new IllegalArgumentException( "value " + tag + " already present" );
314 getMap().put( mtn, tag );
317 private void addReference( final DefaultMutableTreeNode top, Reference ref, final String name ) {
319 ref = new Reference( "" );
321 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
323 addSubelementEditable( category,
324 NodePanel.LIT_REFERENCE_DESC,
325 ref.getDescription(),
326 PHYLOXML_TAG.LIT_REFERENCE_DESC );
327 addSubelementEditable( category, NodePanel.LIT_REFERENCE_DOI, ref.getDoi(), PHYLOXML_TAG.LIT_REFERENCE_DOI );
330 private void addSequence( final DefaultMutableTreeNode top, Sequence seq, final String name ) {
332 seq = new Sequence();
334 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
336 Accession acc = seq.getAccession();
338 acc = new Accession( "", "" );
340 addSubelementEditable( category, NodePanel.SEQ_NAME, seq.getName(), PHYLOXML_TAG.SEQ_NAME );
341 addSubelementEditable( category, NodePanel.SEQ_SYMBOL, seq.getSymbol(), PHYLOXML_TAG.SEQ_SYMBOL );
342 addSubelementEditable( category,
343 NodePanel.SEQ_ACCESSION,
345 PHYLOXML_TAG.SEQ_ACC_VALUE,
348 PHYLOXML_TAG.SEQ_ACC_SOURCE );
349 addSubelementEditable( category, NodePanel.SEQ_LOCATION, seq.getLocation(), PHYLOXML_TAG.SEQ_LOCATION );
350 addSubelementEditable( category, NodePanel.SEQ_TYPE, seq.getType(), PHYLOXML_TAG.SEQ_TYPE );
351 addSubelementEditable( category, NodePanel.SEQ_MOL_SEQ, seq.getMolecularSequence(), PHYLOXML_TAG.SEQ_MOL_SEQ );
353 if ( seq.getUris() != null ) {
354 for( final Uri uri : seq.getUris() ) {
356 addSubelementEditable( category, NodePanel.SEQ_URI + " [" + uri_counter + "]", uri.getValue()
357 .toString(), PHYLOXML_TAG.SEQ_URI, uri_counter++ );
361 addSubelementEditable( category,
362 NodePanel.SEQ_URI + " [" + uri_counter + "]",
364 PHYLOXML_TAG.SEQ_URI,
366 // addAnnotations( top, seq.getAnnotations(), category );
369 private void addSubelementEditable( final DefaultMutableTreeNode node,
372 final PHYLOXML_TAG phyloxml_tag ) {
373 addSubelementEditable( node, name, value, phyloxml_tag, 0 );
376 private void addSubelementEditable( final DefaultMutableTreeNode node,
379 final PHYLOXML_TAG phyloxml_tag,
381 String my_value = value;
382 if ( ForesterUtil.isEmpty( my_value ) ) {
385 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
386 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
387 name_node.add( value_node );
388 node.add( name_node );
389 addMapping( name_node, new TagNumber( phyloxml_tag, number ) );
392 private void addSubelementEditable( final DefaultMutableTreeNode node,
395 final PHYLOXML_TAG phyloxml_value_tag,
396 final String source_name,
397 final String source_value,
398 final PHYLOXML_TAG phyloxml_source_tag ) {
399 addSubelementEditable( node, name, value, phyloxml_value_tag, source_name, source_value, phyloxml_source_tag, 0 );
402 private void addSubelementEditable( final DefaultMutableTreeNode node,
405 final PHYLOXML_TAG phyloxml_value_tag,
406 final String source_name,
407 final String source_value,
408 final PHYLOXML_TAG phyloxml_source_tag,
410 String my_value = value;
411 if ( ForesterUtil.isEmpty( my_value ) ) {
414 String my_source_value = source_value;
415 if ( ForesterUtil.isEmpty( my_source_value ) ) {
416 my_source_value = "";
418 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
419 final DefaultMutableTreeNode source_name_node = new DefaultMutableTreeNode( source_name );
420 final DefaultMutableTreeNode source_value_node = new DefaultMutableTreeNode( my_source_value );
421 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
422 name_node.add( source_name_node );
423 source_name_node.add( source_value_node );
424 name_node.add( value_node );
425 node.add( name_node );
426 addMapping( name_node, new TagNumber( phyloxml_value_tag, number ) );
427 addMapping( source_name_node, new TagNumber( phyloxml_source_tag, number ) );
430 private void addTaxonomy( final DefaultMutableTreeNode top, Taxonomy tax, final String name ) {
432 tax = new Taxonomy();
434 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
436 Identifier id = tax.getIdentifier();
438 id = new Identifier();
440 addSubelementEditable( category,
441 NodePanel.TAXONOMY_IDENTIFIER,
443 PHYLOXML_TAG.TAXONOMY_ID_VALUE,
446 PHYLOXML_TAG.TAXONOMY_ID_PROVIDER );
447 addSubelementEditable( category, NodePanel.TAXONOMY_CODE, tax.getTaxonomyCode(), PHYLOXML_TAG.TAXONOMY_CODE );
448 addSubelementEditable( category,
449 NodePanel.TAXONOMY_SCIENTIFIC_NAME,
450 tax.getScientificName(),
451 PHYLOXML_TAG.TAXONOMY_SCIENTIFIC_NAME );
452 addSubelementEditable( category,
453 NodePanel.TAXONOMY_AUTHORITY,
455 PHYLOXML_TAG.TAXONOMY_AUTHORITY );
456 addSubelementEditable( category,
457 NodePanel.TAXONOMY_COMMON_NAME,
459 PHYLOXML_TAG.TAXONOMY_COMMON_NAME );
460 for( int i = tax.getSynonyms().size() - 1; i >= 0; i-- ) {
461 if ( ForesterUtil.isEmpty( tax.getSynonyms().get( i ) ) ) {
462 tax.getSynonyms().remove( i );
466 for( final String syn : tax.getSynonyms() ) {
467 addSubelementEditable( category,
468 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
470 PHYLOXML_TAG.TAXONOMY_SYNONYM,
473 addSubelementEditable( category,
474 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
476 PHYLOXML_TAG.TAXONOMY_SYNONYM,
478 addSubelementEditable( category, NodePanel.TAXONOMY_RANK, tax.getRank(), PHYLOXML_TAG.TAXONOMY_RANK );
480 if ( tax.getUris() != null ) {
481 for( final Uri uri : tax.getUris() ) {
483 addSubelementEditable( category, NodePanel.TAXONOMY_URI + " [" + uri_counter + "]", uri.getValue()
484 .toString(), PHYLOXML_TAG.TAXONOMY_URI, uri_counter++ );
488 addSubelementEditable( category,
489 NodePanel.TAXONOMY_URI + " [" + uri_counter + "]",
491 PHYLOXML_TAG.TAXONOMY_URI,
495 private void collapsePath( final String name ) {
496 final TreePath tp = getJTree().getNextMatch( name, 0, Position.Bias.Forward );
498 getJTree().collapsePath( tp );
502 private void createNodes( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node ) {
503 if ( !phylogeny_node.getNodeData().isHasTaxonomy() ) {
504 phylogeny_node.getNodeData().addTaxonomy( new Taxonomy() );
506 if ( !phylogeny_node.getNodeData().isHasSequence() ) {
507 phylogeny_node.getNodeData().addSequence( new Sequence() );
509 if ( !phylogeny_node.getNodeData().isHasDistribution() ) {
510 phylogeny_node.getNodeData().addDistribution( new Distribution( "" ) );
512 if ( !phylogeny_node.getNodeData().isHasReference() ) {
513 phylogeny_node.getNodeData().addReference( new Reference( "" ) );
515 addBasics( top, phylogeny_node, NodePanel.BASIC );
516 addTaxonomy( top, phylogeny_node.getNodeData().getTaxonomy(), NodePanel.TAXONOMY );
517 addSequence( top, phylogeny_node.getNodeData().getSequence(), NodePanel.SEQUENCE );
518 if ( !phylogeny_node.isExternal() ) {
519 addEvents( top, phylogeny_node.getNodeData().getEvent(), NodePanel.EVENTS );
521 addDate( top, phylogeny_node.getNodeData().getDate(), NodePanel.DATE );
522 addDistribution( top, phylogeny_node.getNodeData().getDistribution(), NodePanel.DISTRIBUTION );
523 addReference( top, phylogeny_node.getNodeData().getReference(), NodePanel.LIT_REFERENCE );
524 // addProperties( top, phylogeny_node.getNodeData().getProperties(), "Properties" );
527 private void formatError( final DefaultMutableTreeNode mtn, final PhyloXmlDataFormatException e ) {
528 JOptionPane.showMessageDialog( this, e.getMessage(), "Format error", JOptionPane.ERROR_MESSAGE );
529 mtn.setUserObject( "" );
530 getJTree().repaint();
533 private JTree getJTree() {
537 private Map<DefaultMutableTreeNode, TagNumber> getMap() {
541 private TagNumber getMapping( final DefaultMutableTreeNode mtn ) {
542 return getMap().get( mtn );
545 PhylogenyNode getMyNode() {
549 private DefaultMutableTreeNode getSelectedTreeNode() {
550 final TreePath selectionPath = getJTree().getSelectionPath();
551 if ( selectionPath != null ) {
552 final Object[] path = selectionPath.getPath();
553 if ( path.length > 0 ) {
554 return ( DefaultMutableTreeNode ) path[ path.length - 1 ]; // Last node
560 private TreePanel getTreePanel() {
564 private void keyEvent( final KeyEvent e ) {
565 if ( e.getKeyCode() == KeyEvent.VK_ENTER ) {
566 writeBack( getSelectedTreeNode() );
570 private List<Point> obtainPoints() {
571 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
572 Distribution d = getMyNode().getNodeData().getDistribution();
573 if ( d.getPoints() == null ) {
574 d = new Distribution( d.getDesc(), new ArrayList<Point>(), d.getPolygons() );
575 getMyNode().getNodeData().setDistribution( d );
577 final List<Point> ps = d.getPoints();
578 if ( ps.isEmpty() ) {
579 ps.add( new Point() );
581 else if ( ps.get( 0 ) == null ) {
582 ps.set( 0, new Point() );
587 private BigDecimal parseBigDecimal( final DefaultMutableTreeNode mtn, final String value ) {
588 if ( ForesterUtil.isEmpty( value ) ) {
589 return new BigDecimal( 0 );
593 i = new BigDecimal( value );
595 catch ( final NumberFormatException e ) {
596 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
597 mtn.setUserObject( "" );
602 private int parsePositiveInt( final DefaultMutableTreeNode mtn, final String value ) {
603 if ( ForesterUtil.isEmpty( value ) ) {
608 i = ForesterUtil.parseInt( value );
610 catch ( final ParseException e ) {
611 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
612 mtn.setUserObject( "" );
615 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
616 mtn.setUserObject( "" );
622 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
623 final TreePath p = getJTree().getPathForRow( i );
624 writeBack( ( DefaultMutableTreeNode ) p.getLastPathComponent() );
628 private void writeBack( final DefaultMutableTreeNode mtn ) {
629 if ( !getMap().containsKey( mtn ) ) {
630 final DefaultMutableTreeNode parent = ( DefaultMutableTreeNode ) mtn.getParent();
631 if ( getMap().containsKey( parent ) ) {
632 writeBack( mtn, getMapping( parent ) );
637 private void writeBack( final DefaultMutableTreeNode mtn, final TagNumber tag_number ) {
638 if ( tag_number == null ) {
641 String value = mtn.toString();
642 if ( value == null ) {
645 value = value.replaceAll( "\\s+", " " );
646 value = value.trim();
647 mtn.setUserObject( value );
648 getJTree().repaint();
649 final PHYLOXML_TAG tag = tag_number.getTag();
650 final int number = tag_number.getNumber();
653 getMyNode().setName( value );
655 case NODE_BRANCH_LENGTH:
656 if ( ForesterUtil.isEmpty( value ) ) {
657 getMyNode().setDistanceToParent( PhylogenyNode.DISTANCE_DEFAULT );
661 getMyNode().setDistanceToParent( ForesterUtil.parseDouble( value ) );
663 catch ( final ParseException e ) {
664 JOptionPane.showMessageDialog( this,
665 "failed to parse branch length from: " + value,
667 JOptionPane.ERROR_MESSAGE );
668 mtn.setUserObject( "" );
672 case NODE_BRANCH_WIDTH:
673 if ( ForesterUtil.isEmpty( value ) || value.equals( "1" ) ) {
674 if ( getMyNode().getBranchData().getBranchWidth() != null ) {
675 getMyNode().getBranchData().setBranchWidth( new BranchWidth() );
680 final double bw = ForesterUtil.parseDouble( value );
682 getMyNode().getBranchData().setBranchWidth( new BranchWidth(bw ) );
685 catch ( final ParseException e ) {
686 JOptionPane.showMessageDialog( this,
687 "failed to parse branch width from: " + value,
689 JOptionPane.ERROR_MESSAGE );
690 mtn.setUserObject( "" );
694 case CONFIDENCE_VALUE:
695 double confidence = Confidence.CONFIDENCE_DEFAULT_VALUE;
696 if ( !ForesterUtil.isEmpty( value ) ) {
698 confidence = ForesterUtil.parseDouble( value );
700 catch ( final ParseException e ) {
701 JOptionPane.showMessageDialog( this,
702 "failed to parse confidence value from: " + value,
704 JOptionPane.ERROR_MESSAGE );
705 mtn.setUserObject( "" );
709 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
710 throw new FailedConditionCheckException();
712 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
713 if ( confidence >= 0 ) {
714 getMyNode().getBranchData().getConfidences().add( new Confidence( confidence, "unknown" ) );
718 final String type = getMyNode().getBranchData().getConfidences().get( number ).getType();
719 getMyNode().getBranchData().getConfidences().set( number, new Confidence( confidence, type ) );
722 case CONFIDENCE_TYPE:
723 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
724 throw new FailedConditionCheckException();
726 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
727 if ( !ForesterUtil.isEmpty( value ) ) {
728 getMyNode().getBranchData().getConfidences().add( new Confidence( 0, value ) );
732 final double v = getMyNode().getBranchData().getConfidences().get( number ).getValue();
733 getMyNode().getBranchData().getConfidences().set( number, new Confidence( v, value ) );
737 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
739 getMyNode().getNodeData().getTaxonomy().setTaxonomyCode( value );
741 catch ( final PhyloXmlDataFormatException e ) {
742 formatError( mtn, e );
746 case TAXONOMY_SCIENTIFIC_NAME:
747 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
748 getMyNode().getNodeData().getTaxonomy().setScientificName( value );
750 case TAXONOMY_COMMON_NAME:
751 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
752 getMyNode().getNodeData().getTaxonomy().setCommonName( value );
755 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
757 getMyNode().getNodeData().getTaxonomy().setRank( value.toLowerCase() );
759 catch ( final PhyloXmlDataFormatException e ) {
760 formatError( mtn, e );
764 case TAXONOMY_AUTHORITY:
765 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
766 getMyNode().getNodeData().getTaxonomy().setAuthority( value );
770 if ( !ForesterUtil.isEmpty( value ) ) {
772 uri = new Uri( new URL( value ).toURI() );
774 catch ( final Exception e ) {
775 JOptionPane.showMessageDialog( this,
776 "failed to parse URL from: " + value,
778 JOptionPane.ERROR_MESSAGE );
779 mtn.setUserObject( "" );
783 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
785 addUri( mtn, uri, number, getMyNode().getNodeData().getTaxonomy() );
788 case TAXONOMY_SYNONYM:
789 if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() < number ) {
790 throw new FailedConditionCheckException();
792 else if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() == number ) {
793 if ( !ForesterUtil.isEmpty( value ) ) {
794 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
795 getMyNode().getNodeData().getTaxonomy().getSynonyms().add( value );
799 getMyNode().getNodeData().getTaxonomy().getSynonyms().set( number, value );
802 case TAXONOMY_ID_VALUE:
803 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
804 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
805 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value ) );
808 final String provider = getMyNode().getNodeData().getTaxonomy().getIdentifier().getProvider();
809 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value, provider ) );
812 case TAXONOMY_ID_PROVIDER:
813 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
814 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
815 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( "", value ) );
818 final String v = getMyNode().getNodeData().getTaxonomy().getIdentifier().getValue();
819 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( v, value ) );
823 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
824 getMyNode().getNodeData().getSequence().setLocation( value );
827 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
828 getMyNode().getNodeData().getSequence().setMolecularSequence( value );
831 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
832 getMyNode().getNodeData().getSequence().setName( value );
835 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
837 getMyNode().getNodeData().getSequence().setSymbol( value );
839 catch ( final PhyloXmlDataFormatException e ) {
840 formatError( mtn, e );
845 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
847 getMyNode().getNodeData().getSequence().setType( value.toLowerCase() );
849 catch ( final PhyloXmlDataFormatException e ) {
850 formatError( mtn, e );
855 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
856 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
857 getMyNode().getNodeData().getSequence().setAccession( new Accession( "", value ) );
860 final String v = getMyNode().getNodeData().getSequence().getAccession().getValue();
861 getMyNode().getNodeData().getSequence().setAccession( new Accession( v, value ) );
865 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
866 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
867 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, "" ) );
870 final String source = getMyNode().getNodeData().getSequence().getAccession().getSource();
871 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, source ) );
876 if ( !ForesterUtil.isEmpty( value ) ) {
878 uri = new Uri( new URL( value ).toURI() );
880 catch ( final Exception e ) {
881 JOptionPane.showMessageDialog( this,
882 "failed to parse URL from: " + value,
884 JOptionPane.ERROR_MESSAGE );
885 mtn.setUserObject( "" );
889 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
891 addUri( mtn, uri, number, getMyNode().getNodeData().getSequence() );
894 case LIT_REFERENCE_DESC:
895 if ( !getMyNode().getNodeData().isHasReference() ) {
896 getMyNode().getNodeData().setReference( new Reference( "" ) );
898 getMyNode().getNodeData().getReference().setValue( value );
900 case LIT_REFERENCE_DOI:
901 if ( !getMyNode().getNodeData().isHasReference() ) {
902 getMyNode().getNodeData().setReference( new Reference( "" ) );
905 getMyNode().getNodeData().getReference().setDoi( value );
907 catch ( final PhyloXmlDataFormatException e ) {
908 formatError( mtn, e );
912 case EVENTS_DUPLICATIONS:
913 if ( !getMyNode().getNodeData().isHasEvent() ) {
914 getMyNode().getNodeData().setEvent( new Event() );
916 getMyNode().getNodeData().getEvent().setDuplications( parsePositiveInt( mtn, value ) );
918 case EVENTS_SPECIATIONS:
919 if ( !getMyNode().getNodeData().isHasEvent() ) {
920 getMyNode().getNodeData().setEvent( new Event() );
922 getMyNode().getNodeData().getEvent().setSpeciations( parsePositiveInt( mtn, value ) );
924 case EVENTS_GENE_LOSSES:
925 if ( !getMyNode().getNodeData().isHasEvent() ) {
926 getMyNode().getNodeData().setEvent( new Event() );
928 getMyNode().getNodeData().getEvent().setGeneLosses( parsePositiveInt( mtn, value ) );
930 case DATE_DESCRIPTION:
931 ForesterUtil.ensurePresenceOfDate( getMyNode() );
932 getMyNode().getNodeData().getDate().setDesc( value );
935 ForesterUtil.ensurePresenceOfDate( getMyNode() );
936 getMyNode().getNodeData().getDate().setMax( parseBigDecimal( mtn, value ) );
939 ForesterUtil.ensurePresenceOfDate( getMyNode() );
940 getMyNode().getNodeData().getDate().setMin( parseBigDecimal( mtn, value ) );
943 ForesterUtil.ensurePresenceOfDate( getMyNode() );
944 getMyNode().getNodeData().getDate().setUnit( value );
947 ForesterUtil.ensurePresenceOfDate( getMyNode() );
948 getMyNode().getNodeData().getDate().setValue( parseBigDecimal( mtn, value ) );
951 final BigDecimal new_value = parseBigDecimal( mtn, value );
952 if ( new_value != null ) {
953 final List<Point> ps = obtainPoints();
954 final Point p = ps.get( 0 );
955 final Point p_new = new Point( p.getGeodeticDatum(),
959 ForesterUtil.isEmpty( p.getAltiudeUnit() ) ? "?"
960 : p.getAltiudeUnit() );
966 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
967 final Distribution d = getMyNode().getNodeData().getDistribution();
968 getMyNode().getNodeData().setDistribution( new Distribution( value, d.getPoints(), d.getPolygons() ) );
971 case DIST_GEODETIC: {
972 if ( !ForesterUtil.isEmpty( value ) ) {
973 final List<Point> ps = obtainPoints();
974 final Point p = ps.get( 0 );
975 final Point p_new = new Point( value,
979 p.getAltiudeUnit() );
984 case DIST_ALT_UNIT: {
985 if ( !ForesterUtil.isEmpty( value ) ) {
986 final List<Point> ps = obtainPoints();
987 final Point p = ps.get( 0 );
988 final Point p_new = new Point( p.getGeodeticDatum(),
998 final BigDecimal new_value = parseBigDecimal( mtn, value );
999 if ( new_value != null ) {
1000 final List<Point> ps = obtainPoints();
1001 final Point p = ps.get( 0 );
1002 final Point p_new = new Point( p.getGeodeticDatum(),
1006 p.getAltiudeUnit() );
1012 final BigDecimal new_value = parseBigDecimal( mtn, value );
1013 if ( new_value != null ) {
1014 final List<Point> ps = obtainPoints();
1015 final Point p = ps.get( 0 );
1016 final Point p_new = new Point( p.getGeodeticDatum(),
1020 p.getAltiudeUnit() );
1026 throw new IllegalArgumentException( "unknown: " + tag );
1028 getJTree().repaint();
1029 getTreePanel().setEdited( true );
1030 getTreePanel().repaint();
1033 private void addUri( final DefaultMutableTreeNode mtn, final Uri uri, final int number, final MultipleUris mu ) {
1034 if ( uri != null ) {
1035 if ( mu.getUris() == null ) {
1036 mu.setUris( new ArrayList<Uri>() );
1039 if ( ( uri != null ) && ( mu.getUris() == null ) ) {
1040 mu.setUris( new ArrayList<Uri>() );
1042 if ( ( uri != null ) && ( mu.getUris().size() == number ) ) {
1043 mu.getUris().add( uri );
1045 if ( ( mu.getUris() != null ) && ( mu.getUris().size() != number ) ) {
1046 mu.getUris().set( number, uri );
1048 final ImageLoader il = new ImageLoader( getTreePanel() );
1049 new Thread( il ).start();
1052 private enum PHYLOXML_TAG {
1057 TAXONOMY_SCIENTIFIC_NAME,
1059 TAXONOMY_COMMON_NAME,
1075 TAXONOMY_ID_PROVIDER,
1082 EVENTS_DUPLICATIONS,
1093 private class TagNumber {
1095 final private PHYLOXML_TAG _tag;
1096 final private int _number;
1098 TagNumber( final PHYLOXML_TAG tag, final int number ) {
1107 PHYLOXML_TAG getTag() {
1112 public String toString() {
1113 return getTag() + "_" + getNumber();