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.io.parsers.phyloxml.PhyloXmlDataFormatException;
52 import org.forester.phylogeny.PhylogenyNode;
53 import org.forester.phylogeny.data.Accession;
54 import org.forester.phylogeny.data.Confidence;
55 import org.forester.phylogeny.data.Date;
56 import org.forester.phylogeny.data.Distribution;
57 import org.forester.phylogeny.data.Event;
58 import org.forester.phylogeny.data.Identifier;
59 import org.forester.phylogeny.data.MultipleUris;
60 import org.forester.phylogeny.data.PhylogenyData;
61 import org.forester.phylogeny.data.Point;
62 import org.forester.phylogeny.data.Reference;
63 import org.forester.phylogeny.data.Sequence;
64 import org.forester.phylogeny.data.Taxonomy;
65 import org.forester.phylogeny.data.Uri;
66 import org.forester.util.FailedConditionCheckException;
67 import org.forester.util.ForesterUtil;
69 class NodeEditPanel extends JPanel {
71 private static final long serialVersionUID = 5120159904388100771L;
72 private final JTree _tree;
73 private final JEditorPane _pane;
74 private final PhylogenyNode _my_node;
75 private final TreePanel _tree_panel;
76 private final Map<DefaultMutableTreeNode, TagNumber> _map;
78 public NodeEditPanel( final PhylogenyNode phylogeny_node, final TreePanel tree_panel ) {
79 _map = new HashMap<DefaultMutableTreeNode, TagNumber>();
80 _my_node = phylogeny_node;
81 _tree_panel = tree_panel;
82 String node_name = "";
83 if ( !ForesterUtil.isEmpty( phylogeny_node.getName() ) ) {
84 node_name = phylogeny_node.getName() + " ";
86 final DefaultMutableTreeNode top = new DefaultMutableTreeNode( "Node " + node_name );
87 createNodes( top, phylogeny_node );
88 _tree = new JTree( top );
89 getJTree().setEditable( true );
90 getJTree().setFocusable( true );
91 getJTree().setToggleClickCount( 1 );
92 getJTree().setInvokesStopCellEditing( true );
93 final JScrollPane tree_view = new JScrollPane( getJTree() );
94 _pane = new JEditorPane();
95 _pane.setEditable( true );
96 final JScrollPane data_view = new JScrollPane( _pane );
97 final JSplitPane split_pane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
98 split_pane.setTopComponent( tree_view );
99 // split_pane.setBottomComponent( data_view );
100 data_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
101 tree_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
102 // split_pane.setDividerLocation( 400 );
103 split_pane.setPreferredSize( Constants.NODE_PANEL_SIZE );
105 getJTree().getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
106 getJTree().addKeyListener( new KeyListener() {
109 public void keyPressed( final KeyEvent e ) {
114 public void keyReleased( final KeyEvent e ) {
119 public void keyTyped( final KeyEvent e ) {
123 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
124 getJTree().expandRow( i );
126 collapsePath( NodePanel.BASIC );
127 collapsePath( NodePanel.TAXONOMY );
128 collapsePath( NodePanel.SEQUENCE );
129 collapsePath( NodePanel.EVENTS );
130 collapsePath( NodePanel.DATE );
131 collapsePath( NodePanel.DISTRIBUTION );
132 collapsePath( NodePanel.LIT_REFERENCE );
133 getJTree().addTreeSelectionListener( new TreeSelectionListener() {
136 public void valueChanged( final TreeSelectionEvent e ) {
137 final TreePath new_path = e.getNewLeadSelectionPath();
138 final TreePath old_path = e.getOldLeadSelectionPath();
139 if ( new_path != null ) {
140 writeBack( ( DefaultMutableTreeNode ) new_path.getLastPathComponent() );
142 if ( old_path != null ) {
143 writeBack( ( DefaultMutableTreeNode ) old_path.getLastPathComponent() );
149 private void addBasics( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node, final String name ) {
150 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
152 addSubelementEditable( category, NodePanel.NODE_NAME, phylogeny_node.getName(), PHYLOXML_TAG.NODE_NAME );
154 if ( phylogeny_node.getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) {
155 bl = ForesterUtil.FORMATTER_6.format( phylogeny_node.getDistanceToParent() );
157 addSubelementEditable( category, NodePanel.NODE_BRANCH_LENGTH, bl, PHYLOXML_TAG.NODE_BRANCH_LENGTH );
159 if ( phylogeny_node.getBranchData().isHasConfidences() ) {
160 for( int i = phylogeny_node.getBranchData().getConfidences().size() - 1; i >= 0; i-- ) {
161 if ( phylogeny_node.getBranchData().getConfidences().get( i ).getValue() == Confidence.CONFIDENCE_DEFAULT_VALUE ) {
162 phylogeny_node.getBranchData().getConfidences().remove( i );
165 for( final PhylogenyData conf : phylogeny_node.getBranchData().getConfidences() ) {
166 final Confidence my_conf = ( Confidence ) ( conf );
167 addSubelementEditable( category,
168 NodePanel.CONFIDENCE + " [" + counter + "]",
169 ForesterUtil.FORMATTER_6.format( my_conf.getValue() ),
170 PHYLOXML_TAG.CONFIDENCE_VALUE,
171 NodePanel.CONFIDENCE_TYPE,
173 PHYLOXML_TAG.CONFIDENCE_TYPE,
177 addSubelementEditable( category,
178 NodePanel.CONFIDENCE + " [" + counter + "]",
180 PHYLOXML_TAG.CONFIDENCE_VALUE,
181 NodePanel.CONFIDENCE_TYPE,
183 PHYLOXML_TAG.CONFIDENCE_TYPE,
187 // private void addAnnotation( final DefaultMutableTreeNode top, final Annotation ann, final String name ) {
188 // DefaultMutableTreeNode category;
189 // category = new DefaultMutableTreeNode( name );
190 // top.add( category );
191 // addSubelementEditable( category, "Reference", ann.getRef() , PHYLOXML_TAG.);
192 // addSubelementEditable( category, "Description", ann.getDesc() , PHYLOXML_TAG.);
193 // addSubelementEditable( category, "Source", ann.getSource(), PHYLOXML_TAG. );
194 // addSubelementEditable( category, "Type", ann.getType(), PHYLOXML_TAG. );
195 // addSubelementEditable( category, "Evidence", ann.getEvidence() , PHYLOXML_TAG.);
196 // if ( ann.getConfidence() != null ) {
197 // addSubelementEditable( category, "Confidence", ann.getConfidence().asText().toString() , PHYLOXML_TAG.);
199 // if ( ann.getProperties() != null ) {
200 // addProperties( category, ann.getProperties(), "Properties", PHYLOXML_TAG. );
203 // private void addAnnotations( final DefaultMutableTreeNode top,
204 // final List<PhylogenyData> annotations,
205 // final DefaultMutableTreeNode category ) {
206 // if ( ( annotations != null ) && ( annotations.size() > 0 ) ) {
207 // category.add( new DefaultMutableTreeNode( "Annotations" ) );
208 // final DefaultMutableTreeNode last = top.getLastLeaf();
210 // for( final PhylogenyData ann : annotations ) {
211 // addAnnotation( last, ( Annotation ) ann, "Annotation " + ( i++ ) );
215 private void addDate( final DefaultMutableTreeNode top, Date date, final String name ) {
216 if ( date == null ) {
219 DefaultMutableTreeNode category;
220 category = new DefaultMutableTreeNode( name );
222 addSubelementEditable( category, NodePanel.DATE_DESCRIPTION, date.getDesc(), PHYLOXML_TAG.DATE_DESCRIPTION );
223 addSubelementEditable( category,
224 NodePanel.DATE_VALUE,
225 String.valueOf( date.getValue() != null ? date.getValue() : "" ),
226 PHYLOXML_TAG.DATE_VALUE );
227 addSubelementEditable( category,
229 String.valueOf( date.getMin() != null ? date.getMin() : "" ),
230 PHYLOXML_TAG.DATE_MIN );
231 addSubelementEditable( category,
233 String.valueOf( date.getMax() != null ? date.getMax() : "" ),
234 PHYLOXML_TAG.DATE_MAX );
235 addSubelementEditable( category, NodePanel.DATE_UNIT, date.getUnit(), PHYLOXML_TAG.DATE_UNIT );
238 private void addDistribution( final DefaultMutableTreeNode top, Distribution dist, final String name ) {
239 if ( dist == null ) {
240 dist = new Distribution( "" );
242 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
245 if ( ( dist.getPoints() != null ) && ( dist.getPoints().size() > 0 ) ) {
246 p0 = dist.getPoints().get( 0 );
251 addSubelementEditable( category, NodePanel.DIST_DESCRIPTION, dist.getDesc(), PHYLOXML_TAG.DIST_DESC );
252 addSubelementEditable( category,
253 NodePanel.DIST_GEODETIC_DATUM,
254 p0.getGeodeticDatum(),
255 PHYLOXML_TAG.DIST_GEODETIC );
256 addSubelementEditable( category,
257 NodePanel.DIST_LATITUDE,
258 String.valueOf( p0.getLatitude() != null ? p0.getLatitude() : "" ),
259 PHYLOXML_TAG.DIST_LAT );
260 addSubelementEditable( category,
261 NodePanel.DIST_LONGITUDE,
262 String.valueOf( p0.getLongitude() != null ? p0.getLongitude() : "" ),
263 PHYLOXML_TAG.DIST_LONG );
264 addSubelementEditable( category,
265 NodePanel.DIST_ALTITUDE,
266 String.valueOf( p0.getAltitude() != null ? p0.getAltitude() : "" ),
267 PHYLOXML_TAG.DIST_ALT );
268 addSubelementEditable( category,
269 NodePanel.DIST_ALT_UNIT,
270 String.valueOf( p0.getAltiudeUnit() != null ? p0.getAltiudeUnit() : "" ),
271 PHYLOXML_TAG.DIST_ALT_UNIT );
274 private void addEvents( final DefaultMutableTreeNode top, Event events, final String name ) {
275 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
276 if ( events == null ) {
277 events = new Event();
280 addSubelementEditable( category,
281 NodePanel.EVENTS_DUPLICATIONS,
282 String.valueOf( events.getNumberOfDuplications() >= 0 ? events.getNumberOfDuplications()
284 PHYLOXML_TAG.EVENTS_DUPLICATIONS );
285 addSubelementEditable( category,
286 NodePanel.EVENTS_SPECIATIONS,
287 String.valueOf( events.getNumberOfSpeciations() >= 0 ? events.getNumberOfSpeciations()
289 PHYLOXML_TAG.EVENTS_SPECIATIONS );
290 addSubelementEditable( category,
291 NodePanel.EVENTS_GENE_LOSSES,
292 String.valueOf( events.getNumberOfGeneLosses() >= 0 ? events.getNumberOfGeneLosses() : 0 ),
293 PHYLOXML_TAG.EVENTS_GENE_LOSSES );
296 private void addMapping( final DefaultMutableTreeNode mtn, final TagNumber tag ) {
297 if ( getMap().containsKey( mtn ) ) {
298 throw new IllegalArgumentException( "key " + mtn + " already present" );
300 if ( getMap().containsValue( tag ) ) {
301 throw new IllegalArgumentException( "value " + tag + " already present" );
303 getMap().put( mtn, tag );
306 private void addReference( final DefaultMutableTreeNode top, Reference ref, final String name ) {
308 ref = new Reference( "" );
310 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
312 addSubelementEditable( category,
313 NodePanel.LIT_REFERENCE_DESC,
314 ref.getDescription(),
315 PHYLOXML_TAG.LIT_REFERENCE_DESC );
316 addSubelementEditable( category, NodePanel.LIT_REFERENCE_DOI, ref.getDoi(), PHYLOXML_TAG.LIT_REFERENCE_DOI );
319 private void addSequence( final DefaultMutableTreeNode top, Sequence seq, final String name ) {
321 seq = new Sequence();
323 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
325 Accession acc = seq.getAccession();
327 acc = new Accession( "", "" );
329 addSubelementEditable( category, NodePanel.SEQ_NAME, seq.getName(), PHYLOXML_TAG.SEQ_NAME );
330 addSubelementEditable( category, NodePanel.SEQ_SYMBOL, seq.getSymbol(), PHYLOXML_TAG.SEQ_SYMBOL );
331 addSubelementEditable( category,
332 NodePanel.SEQ_ACCESSION,
334 PHYLOXML_TAG.SEQ_ACC_VALUE,
337 PHYLOXML_TAG.SEQ_ACC_SOURCE );
338 addSubelementEditable( category, NodePanel.SEQ_LOCATION, seq.getLocation(), PHYLOXML_TAG.SEQ_LOCATION );
339 addSubelementEditable( category, NodePanel.SEQ_TYPE, seq.getType(), PHYLOXML_TAG.SEQ_TYPE );
340 addSubelementEditable( category, NodePanel.SEQ_MOL_SEQ, seq.getMolecularSequence(), PHYLOXML_TAG.SEQ_MOL_SEQ );
342 if ( seq.getUris() != null ) {
343 for( final Uri uri : seq.getUris() ) {
345 addSubelementEditable( category, NodePanel.SEQ_URI + " [" + uri_counter + "]", uri.getValue()
346 .toString(), PHYLOXML_TAG.SEQ_URI, uri_counter++ );
350 addSubelementEditable( category,
351 NodePanel.SEQ_URI + " [" + uri_counter + "]",
353 PHYLOXML_TAG.SEQ_URI,
355 // addAnnotations( top, seq.getAnnotations(), category );
358 private void addSubelementEditable( final DefaultMutableTreeNode node,
361 final PHYLOXML_TAG phyloxml_tag ) {
362 addSubelementEditable( node, name, value, phyloxml_tag, 0 );
365 private void addSubelementEditable( final DefaultMutableTreeNode node,
368 final PHYLOXML_TAG phyloxml_tag,
370 String my_value = value;
371 if ( ForesterUtil.isEmpty( my_value ) ) {
374 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
375 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
376 name_node.add( value_node );
377 node.add( name_node );
378 addMapping( name_node, new TagNumber( phyloxml_tag, number ) );
381 private void addSubelementEditable( final DefaultMutableTreeNode node,
384 final PHYLOXML_TAG phyloxml_value_tag,
385 final String source_name,
386 final String source_value,
387 final PHYLOXML_TAG phyloxml_source_tag ) {
388 addSubelementEditable( node, name, value, phyloxml_value_tag, source_name, source_value, phyloxml_source_tag, 0 );
391 private void addSubelementEditable( final DefaultMutableTreeNode node,
394 final PHYLOXML_TAG phyloxml_value_tag,
395 final String source_name,
396 final String source_value,
397 final PHYLOXML_TAG phyloxml_source_tag,
399 String my_value = value;
400 if ( ForesterUtil.isEmpty( my_value ) ) {
403 String my_source_value = source_value;
404 if ( ForesterUtil.isEmpty( my_source_value ) ) {
405 my_source_value = "";
407 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
408 final DefaultMutableTreeNode source_name_node = new DefaultMutableTreeNode( source_name );
409 final DefaultMutableTreeNode source_value_node = new DefaultMutableTreeNode( my_source_value );
410 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
411 name_node.add( source_name_node );
412 source_name_node.add( source_value_node );
413 name_node.add( value_node );
414 node.add( name_node );
415 addMapping( name_node, new TagNumber( phyloxml_value_tag, number ) );
416 addMapping( source_name_node, new TagNumber( phyloxml_source_tag, number ) );
419 private void addTaxonomy( final DefaultMutableTreeNode top, Taxonomy tax, final String name ) {
421 tax = new Taxonomy();
423 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
425 Identifier id = tax.getIdentifier();
427 id = new Identifier();
429 addSubelementEditable( category,
430 NodePanel.TAXONOMY_IDENTIFIER,
432 PHYLOXML_TAG.TAXONOMY_ID_VALUE,
435 PHYLOXML_TAG.TAXONOMY_ID_PROVIDER );
436 addSubelementEditable( category, NodePanel.TAXONOMY_CODE, tax.getTaxonomyCode(), PHYLOXML_TAG.TAXONOMY_CODE );
437 addSubelementEditable( category,
438 NodePanel.TAXONOMY_SCIENTIFIC_NAME,
439 tax.getScientificName(),
440 PHYLOXML_TAG.TAXONOMY_SCIENTIFIC_NAME );
441 addSubelementEditable( category,
442 NodePanel.TAXONOMY_AUTHORITY,
444 PHYLOXML_TAG.TAXONOMY_AUTHORITY );
445 addSubelementEditable( category,
446 NodePanel.TAXONOMY_COMMON_NAME,
448 PHYLOXML_TAG.TAXONOMY_COMMON_NAME );
449 for( int i = tax.getSynonyms().size() - 1; i >= 0; i-- ) {
450 if ( ForesterUtil.isEmpty( tax.getSynonyms().get( i ) ) ) {
451 tax.getSynonyms().remove( i );
455 for( final String syn : tax.getSynonyms() ) {
456 addSubelementEditable( category,
457 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
459 PHYLOXML_TAG.TAXONOMY_SYNONYM,
462 addSubelementEditable( category,
463 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
465 PHYLOXML_TAG.TAXONOMY_SYNONYM,
467 addSubelementEditable( category, NodePanel.TAXONOMY_RANK, tax.getRank(), PHYLOXML_TAG.TAXONOMY_RANK );
469 if ( tax.getUris() != null ) {
470 for( final Uri uri : tax.getUris() ) {
472 addSubelementEditable( category, NodePanel.TAXONOMY_URI + " [" + uri_counter + "]", uri.getValue()
473 .toString(), PHYLOXML_TAG.TAXONOMY_URI, uri_counter++ );
477 addSubelementEditable( category,
478 NodePanel.TAXONOMY_URI + " [" + uri_counter + "]",
480 PHYLOXML_TAG.TAXONOMY_URI,
484 private void collapsePath( final String name ) {
485 final TreePath tp = getJTree().getNextMatch( name, 0, Position.Bias.Forward );
487 getJTree().collapsePath( tp );
491 private void createNodes( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node ) {
492 if ( !phylogeny_node.getNodeData().isHasTaxonomy() ) {
493 phylogeny_node.getNodeData().addTaxonomy( new Taxonomy() );
495 if ( !phylogeny_node.getNodeData().isHasSequence() ) {
496 phylogeny_node.getNodeData().addSequence( new Sequence() );
498 if ( !phylogeny_node.getNodeData().isHasDistribution() ) {
499 phylogeny_node.getNodeData().addDistribution( new Distribution( "" ) );
501 if ( !phylogeny_node.getNodeData().isHasReference() ) {
502 phylogeny_node.getNodeData().addReference( new Reference( "" ) );
504 addBasics( top, phylogeny_node, NodePanel.BASIC );
505 addTaxonomy( top, phylogeny_node.getNodeData().getTaxonomy(), NodePanel.TAXONOMY );
506 addSequence( top, phylogeny_node.getNodeData().getSequence(), NodePanel.SEQUENCE );
507 if ( !phylogeny_node.isExternal() ) {
508 addEvents( top, phylogeny_node.getNodeData().getEvent(), NodePanel.EVENTS );
510 addDate( top, phylogeny_node.getNodeData().getDate(), NodePanel.DATE );
511 addDistribution( top, phylogeny_node.getNodeData().getDistribution(), NodePanel.DISTRIBUTION );
512 addReference( top, phylogeny_node.getNodeData().getReference(), NodePanel.LIT_REFERENCE );
513 // addProperties( top, phylogeny_node.getNodeData().getProperties(), "Properties" );
516 private void formatError( final DefaultMutableTreeNode mtn, final PhyloXmlDataFormatException e ) {
517 JOptionPane.showMessageDialog( this, e.getMessage(), "Format error", JOptionPane.ERROR_MESSAGE );
518 mtn.setUserObject( "" );
519 getJTree().repaint();
522 private JTree getJTree() {
526 private Map<DefaultMutableTreeNode, TagNumber> getMap() {
530 private TagNumber getMapping( final DefaultMutableTreeNode mtn ) {
531 return getMap().get( mtn );
534 PhylogenyNode getMyNode() {
538 private DefaultMutableTreeNode getSelectedTreeNode() {
539 final TreePath selectionPath = getJTree().getSelectionPath();
540 if ( selectionPath != null ) {
541 final Object[] path = selectionPath.getPath();
542 if ( path.length > 0 ) {
543 return ( DefaultMutableTreeNode ) path[ path.length - 1 ]; // Last node
549 private TreePanel getTreePanel() {
553 private void keyEvent( final KeyEvent e ) {
554 if ( e.getKeyCode() == KeyEvent.VK_ENTER ) {
555 writeBack( getSelectedTreeNode() );
559 private List<Point> obtainPoints() {
560 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
561 Distribution d = getMyNode().getNodeData().getDistribution();
562 if ( d.getPoints() == null ) {
563 d = new Distribution( d.getDesc(), new ArrayList<Point>(), d.getPolygons() );
564 getMyNode().getNodeData().setDistribution( d );
566 final List<Point> ps = d.getPoints();
567 if ( ps.isEmpty() ) {
568 ps.add( new Point() );
570 else if ( ps.get( 0 ) == null ) {
571 ps.set( 0, new Point() );
576 private BigDecimal parseBigDecimal( final DefaultMutableTreeNode mtn, final String value ) {
577 if ( ForesterUtil.isEmpty( value ) ) {
578 return new BigDecimal( 0 );
582 i = new BigDecimal( value );
584 catch ( final NumberFormatException e ) {
585 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
586 mtn.setUserObject( "" );
591 private int parsePositiveInt( final DefaultMutableTreeNode mtn, final String value ) {
592 if ( ForesterUtil.isEmpty( value ) ) {
597 i = ForesterUtil.parseInt( value );
599 catch ( final ParseException e ) {
600 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
601 mtn.setUserObject( "" );
604 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
605 mtn.setUserObject( "" );
611 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
612 final TreePath p = getJTree().getPathForRow( i );
613 writeBack( ( DefaultMutableTreeNode ) p.getLastPathComponent() );
617 private void writeBack( final DefaultMutableTreeNode mtn ) {
618 if ( !getMap().containsKey( mtn ) ) {
619 final DefaultMutableTreeNode parent = ( DefaultMutableTreeNode ) mtn.getParent();
620 if ( getMap().containsKey( parent ) ) {
621 writeBack( mtn, getMapping( parent ) );
626 private void writeBack( final DefaultMutableTreeNode mtn, final TagNumber tag_number ) {
627 if ( tag_number == null ) {
630 String value = mtn.toString();
631 if ( value == null ) {
634 value = value.replaceAll( "\\s+", " " );
635 value = value.trim();
636 mtn.setUserObject( value );
637 getJTree().repaint();
638 final PHYLOXML_TAG tag = tag_number.getTag();
639 final int number = tag_number.getNumber();
642 getMyNode().setName( value );
644 case NODE_BRANCH_LENGTH:
645 if ( ForesterUtil.isEmpty( value ) ) {
646 getMyNode().setDistanceToParent( PhylogenyNode.DISTANCE_DEFAULT );
650 getMyNode().setDistanceToParent( ForesterUtil.parseDouble( value ) );
652 catch ( final ParseException e ) {
653 JOptionPane.showMessageDialog( this,
654 "failed to parse branch length from: " + value,
656 JOptionPane.ERROR_MESSAGE );
657 mtn.setUserObject( "" );
661 case CONFIDENCE_VALUE:
662 double confidence = Confidence.CONFIDENCE_DEFAULT_VALUE;
663 if ( !ForesterUtil.isEmpty( value ) ) {
665 confidence = ForesterUtil.parseDouble( value );
667 catch ( final ParseException e ) {
668 JOptionPane.showMessageDialog( this,
669 "failed to parse confidence value from: " + value,
671 JOptionPane.ERROR_MESSAGE );
672 mtn.setUserObject( "" );
676 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
677 throw new FailedConditionCheckException();
679 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
680 if ( confidence >= 0 ) {
681 getMyNode().getBranchData().getConfidences().add( new Confidence( confidence, "unknown" ) );
685 final String type = getMyNode().getBranchData().getConfidences().get( number ).getType();
686 getMyNode().getBranchData().getConfidences().set( number, new Confidence( confidence, type ) );
689 case CONFIDENCE_TYPE:
690 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
691 throw new FailedConditionCheckException();
693 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
694 if ( !ForesterUtil.isEmpty( value ) ) {
695 getMyNode().getBranchData().getConfidences().add( new Confidence( 0, value ) );
699 final double v = getMyNode().getBranchData().getConfidences().get( number ).getValue();
700 getMyNode().getBranchData().getConfidences().set( number, new Confidence( v, value ) );
704 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
706 getMyNode().getNodeData().getTaxonomy().setTaxonomyCode( value );
708 catch ( final PhyloXmlDataFormatException e ) {
709 formatError( mtn, e );
713 case TAXONOMY_SCIENTIFIC_NAME:
714 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
715 getMyNode().getNodeData().getTaxonomy().setScientificName( value );
717 case TAXONOMY_COMMON_NAME:
718 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
719 getMyNode().getNodeData().getTaxonomy().setCommonName( value );
722 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
724 getMyNode().getNodeData().getTaxonomy().setRank( value.toLowerCase() );
726 catch ( final PhyloXmlDataFormatException e ) {
727 formatError( mtn, e );
731 case TAXONOMY_AUTHORITY:
732 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
733 getMyNode().getNodeData().getTaxonomy().setAuthority( value );
737 if ( !ForesterUtil.isEmpty( value ) ) {
739 uri = new Uri( new URL( value ).toURI() );
741 catch ( final Exception e ) {
742 JOptionPane.showMessageDialog( this,
743 "failed to parse URL from: " + value,
745 JOptionPane.ERROR_MESSAGE );
746 mtn.setUserObject( "" );
750 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
752 addUri( mtn, uri, number, getMyNode().getNodeData().getTaxonomy() );
755 case TAXONOMY_SYNONYM:
756 if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() < number ) {
757 throw new FailedConditionCheckException();
759 else if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() == number ) {
760 if ( !ForesterUtil.isEmpty( value ) ) {
761 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
762 getMyNode().getNodeData().getTaxonomy().getSynonyms().add( value );
766 getMyNode().getNodeData().getTaxonomy().getSynonyms().set( number, value );
769 case TAXONOMY_ID_VALUE:
770 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
771 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
772 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value ) );
775 final String provider = getMyNode().getNodeData().getTaxonomy().getIdentifier().getProvider();
776 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value, provider ) );
779 case TAXONOMY_ID_PROVIDER:
780 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
781 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
782 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( "", value ) );
785 final String v = getMyNode().getNodeData().getTaxonomy().getIdentifier().getValue();
786 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( v, value ) );
790 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
791 getMyNode().getNodeData().getSequence().setLocation( value );
794 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
795 getMyNode().getNodeData().getSequence().setMolecularSequence( value );
798 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
799 getMyNode().getNodeData().getSequence().setName( value );
802 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
804 getMyNode().getNodeData().getSequence().setSymbol( value );
806 catch ( final PhyloXmlDataFormatException e ) {
807 formatError( mtn, e );
812 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
814 getMyNode().getNodeData().getSequence().setType( value.toLowerCase() );
816 catch ( final PhyloXmlDataFormatException e ) {
817 formatError( mtn, e );
822 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
823 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
824 getMyNode().getNodeData().getSequence().setAccession( new Accession( "", value ) );
827 final String v = getMyNode().getNodeData().getSequence().getAccession().getValue();
828 getMyNode().getNodeData().getSequence().setAccession( new Accession( v, value ) );
832 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
833 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
834 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, "" ) );
837 final String source = getMyNode().getNodeData().getSequence().getAccession().getSource();
838 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, source ) );
843 if ( !ForesterUtil.isEmpty( value ) ) {
845 uri = new Uri( new URL( value ).toURI() );
847 catch ( final Exception e ) {
848 JOptionPane.showMessageDialog( this,
849 "failed to parse URL from: " + value,
851 JOptionPane.ERROR_MESSAGE );
852 mtn.setUserObject( "" );
856 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
858 addUri( mtn, uri, number, getMyNode().getNodeData().getSequence() );
861 case LIT_REFERENCE_DESC:
862 if ( !getMyNode().getNodeData().isHasReference() ) {
863 getMyNode().getNodeData().setReference( new Reference( "" ) );
865 getMyNode().getNodeData().getReference().setValue( value );
867 case LIT_REFERENCE_DOI:
868 if ( !getMyNode().getNodeData().isHasReference() ) {
869 getMyNode().getNodeData().setReference( new Reference( "" ) );
872 getMyNode().getNodeData().getReference().setDoi( value );
874 catch ( final PhyloXmlDataFormatException e ) {
875 formatError( mtn, e );
879 case EVENTS_DUPLICATIONS:
880 if ( !getMyNode().getNodeData().isHasEvent() ) {
881 getMyNode().getNodeData().setEvent( new Event() );
883 getMyNode().getNodeData().getEvent().setDuplications( parsePositiveInt( mtn, value ) );
885 case EVENTS_SPECIATIONS:
886 if ( !getMyNode().getNodeData().isHasEvent() ) {
887 getMyNode().getNodeData().setEvent( new Event() );
889 getMyNode().getNodeData().getEvent().setSpeciations( parsePositiveInt( mtn, value ) );
891 case EVENTS_GENE_LOSSES:
892 if ( !getMyNode().getNodeData().isHasEvent() ) {
893 getMyNode().getNodeData().setEvent( new Event() );
895 getMyNode().getNodeData().getEvent().setGeneLosses( parsePositiveInt( mtn, value ) );
897 case DATE_DESCRIPTION:
898 ForesterUtil.ensurePresenceOfDate( getMyNode() );
899 getMyNode().getNodeData().getDate().setDesc( value );
902 ForesterUtil.ensurePresenceOfDate( getMyNode() );
903 getMyNode().getNodeData().getDate().setMax( parseBigDecimal( mtn, value ) );
906 ForesterUtil.ensurePresenceOfDate( getMyNode() );
907 getMyNode().getNodeData().getDate().setMin( parseBigDecimal( mtn, value ) );
910 ForesterUtil.ensurePresenceOfDate( getMyNode() );
911 getMyNode().getNodeData().getDate().setUnit( value );
914 ForesterUtil.ensurePresenceOfDate( getMyNode() );
915 getMyNode().getNodeData().getDate().setValue( parseBigDecimal( mtn, value ) );
918 final BigDecimal new_value = parseBigDecimal( mtn, value );
919 if ( new_value != null ) {
920 final List<Point> ps = obtainPoints();
921 final Point p = ps.get( 0 );
922 final Point p_new = new Point( p.getGeodeticDatum(),
926 ForesterUtil.isEmpty( p.getAltiudeUnit() ) ? "?"
927 : p.getAltiudeUnit() );
933 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
934 final Distribution d = getMyNode().getNodeData().getDistribution();
935 getMyNode().getNodeData().setDistribution( new Distribution( value, d.getPoints(), d.getPolygons() ) );
938 case DIST_GEODETIC: {
939 if ( !ForesterUtil.isEmpty( value ) ) {
940 final List<Point> ps = obtainPoints();
941 final Point p = ps.get( 0 );
942 final Point p_new = new Point( value,
946 p.getAltiudeUnit() );
951 case DIST_ALT_UNIT: {
952 if ( !ForesterUtil.isEmpty( value ) ) {
953 final List<Point> ps = obtainPoints();
954 final Point p = ps.get( 0 );
955 final Point p_new = new Point( p.getGeodeticDatum(),
965 final BigDecimal new_value = parseBigDecimal( mtn, value );
966 if ( new_value != null ) {
967 final List<Point> ps = obtainPoints();
968 final Point p = ps.get( 0 );
969 final Point p_new = new Point( p.getGeodeticDatum(),
973 p.getAltiudeUnit() );
979 final BigDecimal new_value = parseBigDecimal( mtn, value );
980 if ( new_value != null ) {
981 final List<Point> ps = obtainPoints();
982 final Point p = ps.get( 0 );
983 final Point p_new = new Point( p.getGeodeticDatum(),
987 p.getAltiudeUnit() );
993 throw new IllegalArgumentException( "unknown: " + tag );
995 getJTree().repaint();
996 getTreePanel().setEdited( true );
997 getTreePanel().repaint();
1000 private void addUri( final DefaultMutableTreeNode mtn, final Uri uri, final int number, final MultipleUris mu ) {
1001 if ( uri != null ) {
1002 if ( mu.getUris() == null ) {
1003 mu.setUris( new ArrayList<Uri>() );
1006 if ( ( uri != null ) && ( mu.getUris() == null ) ) {
1007 mu.setUris( new ArrayList<Uri>() );
1009 if ( ( uri != null ) && ( mu.getUris().size() == number ) ) {
1010 mu.getUris().add( uri );
1012 if ( ( mu.getUris() != null ) && ( mu.getUris().size() != number ) ) {
1013 mu.getUris().set( number, uri );
1015 final ImageLoader il = new ImageLoader( getTreePanel() );
1016 new Thread( il ).start();
1019 private enum PHYLOXML_TAG {
1023 TAXONOMY_SCIENTIFIC_NAME,
1025 TAXONOMY_COMMON_NAME,
1041 TAXONOMY_ID_PROVIDER,
1048 EVENTS_DUPLICATIONS,
1059 private class TagNumber {
1061 final private PHYLOXML_TAG _tag;
1062 final private int _number;
1064 TagNumber( final PHYLOXML_TAG tag, final int number ) {
1073 PHYLOXML_TAG getTag() {
1078 public String toString() {
1079 return getTag() + "_" + getNumber();