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.Confidence;
56 import org.forester.phylogeny.data.Date;
57 import org.forester.phylogeny.data.Distribution;
58 import org.forester.phylogeny.data.Event;
59 import org.forester.phylogeny.data.Identifier;
60 import org.forester.phylogeny.data.MultipleUris;
61 import org.forester.phylogeny.data.PhylogenyData;
62 import org.forester.phylogeny.data.Point;
63 import org.forester.phylogeny.data.Reference;
64 import org.forester.phylogeny.data.Sequence;
65 import org.forester.phylogeny.data.Taxonomy;
66 import org.forester.phylogeny.data.Uri;
67 import org.forester.util.FailedConditionCheckException;
68 import org.forester.util.ForesterUtil;
70 class NodeEditPanel extends JPanel {
72 private static final long serialVersionUID = 5120159904388100771L;
73 private final JTree _tree;
74 private final JEditorPane _pane;
75 private final PhylogenyNode _my_node;
76 private final TreePanel _tree_panel;
77 private final Map<DefaultMutableTreeNode, TagNumber> _map;
79 public NodeEditPanel( final PhylogenyNode phylogeny_node, final TreePanel tree_panel ) {
80 _map = new HashMap<DefaultMutableTreeNode, TagNumber>();
81 _my_node = phylogeny_node;
82 _tree_panel = tree_panel;
83 String node_name = "";
84 if ( !ForesterUtil.isEmpty( phylogeny_node.getName() ) ) {
85 node_name = phylogeny_node.getName() + " ";
87 final DefaultMutableTreeNode top = new DefaultMutableTreeNode( "Node " + node_name );
88 createNodes( top, phylogeny_node );
89 _tree = new JTree( top );
90 getJTree().setEditable( true );
91 getJTree().setFocusable( true );
92 getJTree().setToggleClickCount( 1 );
93 getJTree().setInvokesStopCellEditing( true );
94 final JScrollPane tree_view = new JScrollPane( getJTree() );
95 _pane = new JEditorPane();
96 _pane.setEditable( true );
97 final JScrollPane data_view = new JScrollPane( _pane );
98 final JSplitPane split_pane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
99 split_pane.setTopComponent( tree_view );
100 // split_pane.setBottomComponent( data_view );
101 data_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
102 tree_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
103 // split_pane.setDividerLocation( 400 );
104 split_pane.setPreferredSize( Constants.NODE_PANEL_SIZE );
106 getJTree().getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
107 getJTree().addKeyListener( new KeyListener() {
110 public void keyPressed( final KeyEvent e ) {
115 public void keyReleased( final KeyEvent e ) {
120 public void keyTyped( final KeyEvent e ) {
124 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
125 getJTree().expandRow( i );
127 collapsePath( NodePanel.BASIC );
128 collapsePath( NodePanel.TAXONOMY );
129 collapsePath( NodePanel.SEQUENCE );
130 collapsePath( NodePanel.EVENTS );
131 collapsePath( NodePanel.DATE );
132 collapsePath( NodePanel.DISTRIBUTION );
133 collapsePath( NodePanel.LIT_REFERENCE );
134 getJTree().addTreeSelectionListener( new TreeSelectionListener() {
137 public void valueChanged( final TreeSelectionEvent e ) {
138 final TreePath new_path = e.getNewLeadSelectionPath();
139 final TreePath old_path = e.getOldLeadSelectionPath();
140 if ( new_path != null ) {
141 writeBack( ( DefaultMutableTreeNode ) new_path.getLastPathComponent() );
143 if ( old_path != null ) {
144 writeBack( ( DefaultMutableTreeNode ) old_path.getLastPathComponent() );
150 private void addBasics( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node, final String name ) {
151 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
153 addSubelementEditable( category, NodePanel.NODE_NAME, phylogeny_node.getName(), PHYLOXML_TAG.NODE_NAME );
155 if ( phylogeny_node.getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) {
156 bl = ForesterUtil.FORMATTER_6.format( phylogeny_node.getDistanceToParent() );
158 addSubelementEditable( category, NodePanel.NODE_BRANCH_LENGTH, bl, PHYLOXML_TAG.NODE_BRANCH_LENGTH );
160 if ( phylogeny_node.getBranchData().isHasConfidences() ) {
161 for( int i = phylogeny_node.getBranchData().getConfidences().size() - 1; i >= 0; i-- ) {
162 if ( phylogeny_node.getBranchData().getConfidences().get( i ).getValue() == Confidence.CONFIDENCE_DEFAULT_VALUE ) {
163 phylogeny_node.getBranchData().getConfidences().remove( i );
166 for( final PhylogenyData conf : phylogeny_node.getBranchData().getConfidences() ) {
167 final Confidence my_conf = ( Confidence ) ( conf );
168 addSubelementEditable( category,
169 NodePanel.CONFIDENCE + " [" + counter + "]",
170 ForesterUtil.FORMATTER_6.format( my_conf.getValue() ),
171 PHYLOXML_TAG.CONFIDENCE_VALUE,
172 NodePanel.CONFIDENCE_TYPE,
174 PHYLOXML_TAG.CONFIDENCE_TYPE,
178 addSubelementEditable( category,
179 NodePanel.CONFIDENCE + " [" + counter + "]",
181 PHYLOXML_TAG.CONFIDENCE_VALUE,
182 NodePanel.CONFIDENCE_TYPE,
184 PHYLOXML_TAG.CONFIDENCE_TYPE,
188 // private void addAnnotation( final DefaultMutableTreeNode top, final Annotation ann, final String name ) {
189 // DefaultMutableTreeNode category;
190 // category = new DefaultMutableTreeNode( name );
191 // top.add( category );
192 // addSubelementEditable( category, "Reference", ann.getRef() , PHYLOXML_TAG.);
193 // addSubelementEditable( category, "Description", ann.getDesc() , PHYLOXML_TAG.);
194 // addSubelementEditable( category, "Source", ann.getSource(), PHYLOXML_TAG. );
195 // addSubelementEditable( category, "Type", ann.getType(), PHYLOXML_TAG. );
196 // addSubelementEditable( category, "Evidence", ann.getEvidence() , PHYLOXML_TAG.);
197 // if ( ann.getConfidence() != null ) {
198 // addSubelementEditable( category, "Confidence", ann.getConfidence().asText().toString() , PHYLOXML_TAG.);
200 // if ( ann.getProperties() != null ) {
201 // addProperties( category, ann.getProperties(), "Properties", PHYLOXML_TAG. );
204 // private void addAnnotations( final DefaultMutableTreeNode top,
205 // final List<PhylogenyData> annotations,
206 // final DefaultMutableTreeNode category ) {
207 // if ( ( annotations != null ) && ( annotations.size() > 0 ) ) {
208 // category.add( new DefaultMutableTreeNode( "Annotations" ) );
209 // final DefaultMutableTreeNode last = top.getLastLeaf();
211 // for( final PhylogenyData ann : annotations ) {
212 // addAnnotation( last, ( Annotation ) ann, "Annotation " + ( i++ ) );
216 private void addDate( final DefaultMutableTreeNode top, Date date, final String name ) {
217 if ( date == null ) {
220 DefaultMutableTreeNode category;
221 category = new DefaultMutableTreeNode( name );
223 addSubelementEditable( category, NodePanel.DATE_DESCRIPTION, date.getDesc(), PHYLOXML_TAG.DATE_DESCRIPTION );
224 addSubelementEditable( category,
225 NodePanel.DATE_VALUE,
226 String.valueOf( date.getValue() != null ? date.getValue() : "" ),
227 PHYLOXML_TAG.DATE_VALUE );
228 addSubelementEditable( category,
230 String.valueOf( date.getMin() != null ? date.getMin() : "" ),
231 PHYLOXML_TAG.DATE_MIN );
232 addSubelementEditable( category,
234 String.valueOf( date.getMax() != null ? date.getMax() : "" ),
235 PHYLOXML_TAG.DATE_MAX );
236 addSubelementEditable( category, NodePanel.DATE_UNIT, date.getUnit(), PHYLOXML_TAG.DATE_UNIT );
239 private void addDistribution( final DefaultMutableTreeNode top, Distribution dist, final String name ) {
240 if ( dist == null ) {
241 dist = new Distribution( "" );
243 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
246 if ( ( dist.getPoints() != null ) && ( dist.getPoints().size() > 0 ) ) {
247 p0 = dist.getPoints().get( 0 );
252 addSubelementEditable( category, NodePanel.DIST_DESCRIPTION, dist.getDesc(), PHYLOXML_TAG.DIST_DESC );
253 addSubelementEditable( category,
254 NodePanel.DIST_GEODETIC_DATUM,
255 p0.getGeodeticDatum(),
256 PHYLOXML_TAG.DIST_GEODETIC );
257 addSubelementEditable( category,
258 NodePanel.DIST_LATITUDE,
259 String.valueOf( p0.getLatitude() != null ? p0.getLatitude() : "" ),
260 PHYLOXML_TAG.DIST_LAT );
261 addSubelementEditable( category,
262 NodePanel.DIST_LONGITUDE,
263 String.valueOf( p0.getLongitude() != null ? p0.getLongitude() : "" ),
264 PHYLOXML_TAG.DIST_LONG );
265 addSubelementEditable( category,
266 NodePanel.DIST_ALTITUDE,
267 String.valueOf( p0.getAltitude() != null ? p0.getAltitude() : "" ),
268 PHYLOXML_TAG.DIST_ALT );
269 addSubelementEditable( category,
270 NodePanel.DIST_ALT_UNIT,
271 String.valueOf( p0.getAltiudeUnit() != null ? p0.getAltiudeUnit() : "" ),
272 PHYLOXML_TAG.DIST_ALT_UNIT );
275 private void addEvents( final DefaultMutableTreeNode top, Event events, final String name ) {
276 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
277 if ( events == null ) {
278 events = new Event();
281 addSubelementEditable( category,
282 NodePanel.EVENTS_DUPLICATIONS,
283 String.valueOf( events.getNumberOfDuplications() >= 0 ? events.getNumberOfDuplications()
285 PHYLOXML_TAG.EVENTS_DUPLICATIONS );
286 addSubelementEditable( category,
287 NodePanel.EVENTS_SPECIATIONS,
288 String.valueOf( events.getNumberOfSpeciations() >= 0 ? events.getNumberOfSpeciations()
290 PHYLOXML_TAG.EVENTS_SPECIATIONS );
291 addSubelementEditable( category,
292 NodePanel.EVENTS_GENE_LOSSES,
293 String.valueOf( events.getNumberOfGeneLosses() >= 0 ? events.getNumberOfGeneLosses() : 0 ),
294 PHYLOXML_TAG.EVENTS_GENE_LOSSES );
297 private void addMapping( final DefaultMutableTreeNode mtn, final TagNumber tag ) {
298 if ( getMap().containsKey( mtn ) ) {
299 throw new IllegalArgumentException( "key " + mtn + " already present" );
301 if ( getMap().containsValue( tag ) ) {
302 throw new IllegalArgumentException( "value " + tag + " already present" );
304 getMap().put( mtn, tag );
307 private void addReference( final DefaultMutableTreeNode top, Reference ref, final String name ) {
309 ref = new Reference( "" );
311 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
313 addSubelementEditable( category,
314 NodePanel.LIT_REFERENCE_DESC,
315 ref.getDescription(),
316 PHYLOXML_TAG.LIT_REFERENCE_DESC );
317 addSubelementEditable( category, NodePanel.LIT_REFERENCE_DOI, ref.getDoi(), PHYLOXML_TAG.LIT_REFERENCE_DOI );
320 private void addSequence( final DefaultMutableTreeNode top, Sequence seq, final String name ) {
322 seq = new Sequence();
324 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
326 Accession acc = seq.getAccession();
328 acc = new Accession( "", "" );
330 addSubelementEditable( category, NodePanel.SEQ_NAME, seq.getName(), PHYLOXML_TAG.SEQ_NAME );
331 addSubelementEditable( category, NodePanel.SEQ_SYMBOL, seq.getSymbol(), PHYLOXML_TAG.SEQ_SYMBOL );
332 addSubelementEditable( category,
333 NodePanel.SEQ_ACCESSION,
335 PHYLOXML_TAG.SEQ_ACC_VALUE,
338 PHYLOXML_TAG.SEQ_ACC_SOURCE );
339 addSubelementEditable( category, NodePanel.SEQ_LOCATION, seq.getLocation(), PHYLOXML_TAG.SEQ_LOCATION );
340 addSubelementEditable( category, NodePanel.SEQ_TYPE, seq.getType(), PHYLOXML_TAG.SEQ_TYPE );
341 addSubelementEditable( category, NodePanel.SEQ_MOL_SEQ, seq.getMolecularSequence(), PHYLOXML_TAG.SEQ_MOL_SEQ );
343 if ( seq.getUris() != null ) {
344 for( final Uri uri : seq.getUris() ) {
346 addSubelementEditable( category, NodePanel.SEQ_URI + " [" + uri_counter + "]", uri.getValue()
347 .toString(), PHYLOXML_TAG.SEQ_URI, uri_counter++ );
351 addSubelementEditable( category,
352 NodePanel.SEQ_URI + " [" + uri_counter + "]",
354 PHYLOXML_TAG.SEQ_URI,
356 // addAnnotations( top, seq.getAnnotations(), category );
359 private void addSubelementEditable( final DefaultMutableTreeNode node,
362 final PHYLOXML_TAG phyloxml_tag ) {
363 addSubelementEditable( node, name, value, phyloxml_tag, 0 );
366 private void addSubelementEditable( final DefaultMutableTreeNode node,
369 final PHYLOXML_TAG phyloxml_tag,
371 String my_value = value;
372 if ( ForesterUtil.isEmpty( my_value ) ) {
375 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
376 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
377 name_node.add( value_node );
378 node.add( name_node );
379 addMapping( name_node, new TagNumber( phyloxml_tag, number ) );
382 private void addSubelementEditable( final DefaultMutableTreeNode node,
385 final PHYLOXML_TAG phyloxml_value_tag,
386 final String source_name,
387 final String source_value,
388 final PHYLOXML_TAG phyloxml_source_tag ) {
389 addSubelementEditable( node, name, value, phyloxml_value_tag, source_name, source_value, phyloxml_source_tag, 0 );
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,
400 String my_value = value;
401 if ( ForesterUtil.isEmpty( my_value ) ) {
404 String my_source_value = source_value;
405 if ( ForesterUtil.isEmpty( my_source_value ) ) {
406 my_source_value = "";
408 final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
409 final DefaultMutableTreeNode source_name_node = new DefaultMutableTreeNode( source_name );
410 final DefaultMutableTreeNode source_value_node = new DefaultMutableTreeNode( my_source_value );
411 final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
412 name_node.add( source_name_node );
413 source_name_node.add( source_value_node );
414 name_node.add( value_node );
415 node.add( name_node );
416 addMapping( name_node, new TagNumber( phyloxml_value_tag, number ) );
417 addMapping( source_name_node, new TagNumber( phyloxml_source_tag, number ) );
420 private void addTaxonomy( final DefaultMutableTreeNode top, Taxonomy tax, final String name ) {
422 tax = new Taxonomy();
424 final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
426 Identifier id = tax.getIdentifier();
428 id = new Identifier();
430 addSubelementEditable( category,
431 NodePanel.TAXONOMY_IDENTIFIER,
433 PHYLOXML_TAG.TAXONOMY_ID_VALUE,
436 PHYLOXML_TAG.TAXONOMY_ID_PROVIDER );
437 addSubelementEditable( category, NodePanel.TAXONOMY_CODE, tax.getTaxonomyCode(), PHYLOXML_TAG.TAXONOMY_CODE );
438 addSubelementEditable( category,
439 NodePanel.TAXONOMY_SCIENTIFIC_NAME,
440 tax.getScientificName(),
441 PHYLOXML_TAG.TAXONOMY_SCIENTIFIC_NAME );
442 addSubelementEditable( category,
443 NodePanel.TAXONOMY_AUTHORITY,
445 PHYLOXML_TAG.TAXONOMY_AUTHORITY );
446 addSubelementEditable( category,
447 NodePanel.TAXONOMY_COMMON_NAME,
449 PHYLOXML_TAG.TAXONOMY_COMMON_NAME );
450 for( int i = tax.getSynonyms().size() - 1; i >= 0; i-- ) {
451 if ( ForesterUtil.isEmpty( tax.getSynonyms().get( i ) ) ) {
452 tax.getSynonyms().remove( i );
456 for( final String syn : tax.getSynonyms() ) {
457 addSubelementEditable( category,
458 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
460 PHYLOXML_TAG.TAXONOMY_SYNONYM,
463 addSubelementEditable( category,
464 NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
466 PHYLOXML_TAG.TAXONOMY_SYNONYM,
468 addSubelementEditable( category, NodePanel.TAXONOMY_RANK, tax.getRank(), PHYLOXML_TAG.TAXONOMY_RANK );
470 if ( tax.getUris() != null ) {
471 for( final Uri uri : tax.getUris() ) {
473 addSubelementEditable( category, NodePanel.TAXONOMY_URI + " [" + uri_counter + "]", uri.getValue()
474 .toString(), PHYLOXML_TAG.TAXONOMY_URI, uri_counter++ );
478 addSubelementEditable( category,
479 NodePanel.TAXONOMY_URI + " [" + uri_counter + "]",
481 PHYLOXML_TAG.TAXONOMY_URI,
485 private void collapsePath( final String name ) {
486 final TreePath tp = getJTree().getNextMatch( name, 0, Position.Bias.Forward );
488 getJTree().collapsePath( tp );
492 private void createNodes( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node ) {
493 if ( !phylogeny_node.getNodeData().isHasTaxonomy() ) {
494 phylogeny_node.getNodeData().addTaxonomy( new Taxonomy() );
496 if ( !phylogeny_node.getNodeData().isHasSequence() ) {
497 phylogeny_node.getNodeData().addSequence( new Sequence() );
499 if ( !phylogeny_node.getNodeData().isHasDistribution() ) {
500 phylogeny_node.getNodeData().addDistribution( new Distribution( "" ) );
502 if ( !phylogeny_node.getNodeData().isHasReference() ) {
503 phylogeny_node.getNodeData().addReference( new Reference( "" ) );
505 addBasics( top, phylogeny_node, NodePanel.BASIC );
506 addTaxonomy( top, phylogeny_node.getNodeData().getTaxonomy(), NodePanel.TAXONOMY );
507 addSequence( top, phylogeny_node.getNodeData().getSequence(), NodePanel.SEQUENCE );
508 if ( !phylogeny_node.isExternal() ) {
509 addEvents( top, phylogeny_node.getNodeData().getEvent(), NodePanel.EVENTS );
511 addDate( top, phylogeny_node.getNodeData().getDate(), NodePanel.DATE );
512 addDistribution( top, phylogeny_node.getNodeData().getDistribution(), NodePanel.DISTRIBUTION );
513 addReference( top, phylogeny_node.getNodeData().getReference(), NodePanel.LIT_REFERENCE );
514 // addProperties( top, phylogeny_node.getNodeData().getProperties(), "Properties" );
517 private void formatError( final DefaultMutableTreeNode mtn, final PhyloXmlDataFormatException e ) {
518 JOptionPane.showMessageDialog( this, e.getMessage(), "Format error", JOptionPane.ERROR_MESSAGE );
519 mtn.setUserObject( "" );
520 getJTree().repaint();
523 private JTree getJTree() {
527 private Map<DefaultMutableTreeNode, TagNumber> getMap() {
531 private TagNumber getMapping( final DefaultMutableTreeNode mtn ) {
532 return getMap().get( mtn );
535 PhylogenyNode getMyNode() {
539 private DefaultMutableTreeNode getSelectedTreeNode() {
540 final TreePath selectionPath = getJTree().getSelectionPath();
541 if ( selectionPath != null ) {
542 final Object[] path = selectionPath.getPath();
543 if ( path.length > 0 ) {
544 return ( DefaultMutableTreeNode ) path[ path.length - 1 ]; // Last node
550 private TreePanel getTreePanel() {
554 private void keyEvent( final KeyEvent e ) {
555 if ( e.getKeyCode() == KeyEvent.VK_ENTER ) {
556 writeBack( getSelectedTreeNode() );
560 private List<Point> obtainPoints() {
561 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
562 Distribution d = getMyNode().getNodeData().getDistribution();
563 if ( d.getPoints() == null ) {
564 d = new Distribution( d.getDesc(), new ArrayList<Point>(), d.getPolygons() );
565 getMyNode().getNodeData().setDistribution( d );
567 final List<Point> ps = d.getPoints();
568 if ( ps.isEmpty() ) {
569 ps.add( new Point() );
571 else if ( ps.get( 0 ) == null ) {
572 ps.set( 0, new Point() );
577 private BigDecimal parseBigDecimal( final DefaultMutableTreeNode mtn, final String value ) {
578 if ( ForesterUtil.isEmpty( value ) ) {
579 return new BigDecimal( 0 );
583 i = new BigDecimal( value );
585 catch ( final NumberFormatException e ) {
586 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
587 mtn.setUserObject( "" );
592 private int parsePositiveInt( final DefaultMutableTreeNode mtn, final String value ) {
593 if ( ForesterUtil.isEmpty( value ) ) {
598 i = ForesterUtil.parseInt( value );
600 catch ( final ParseException e ) {
601 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
602 mtn.setUserObject( "" );
605 JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
606 mtn.setUserObject( "" );
612 for( int i = 0; i < getJTree().getRowCount(); i++ ) {
613 final TreePath p = getJTree().getPathForRow( i );
614 writeBack( ( DefaultMutableTreeNode ) p.getLastPathComponent() );
618 private void writeBack( final DefaultMutableTreeNode mtn ) {
619 if ( !getMap().containsKey( mtn ) ) {
620 final DefaultMutableTreeNode parent = ( DefaultMutableTreeNode ) mtn.getParent();
621 if ( getMap().containsKey( parent ) ) {
622 writeBack( mtn, getMapping( parent ) );
627 private void writeBack( final DefaultMutableTreeNode mtn, final TagNumber tag_number ) {
628 if ( tag_number == null ) {
631 String value = mtn.toString();
632 if ( value == null ) {
635 value = value.replaceAll( "\\s+", " " );
636 value = value.trim();
637 mtn.setUserObject( value );
638 getJTree().repaint();
639 final PHYLOXML_TAG tag = tag_number.getTag();
640 final int number = tag_number.getNumber();
643 getMyNode().setName( value );
645 case NODE_BRANCH_LENGTH:
646 if ( ForesterUtil.isEmpty( value ) ) {
647 getMyNode().setDistanceToParent( PhylogenyNode.DISTANCE_DEFAULT );
651 getMyNode().setDistanceToParent( ForesterUtil.parseDouble( value ) );
653 catch ( final ParseException e ) {
654 JOptionPane.showMessageDialog( this,
655 "failed to parse branch length from: " + value,
657 JOptionPane.ERROR_MESSAGE );
658 mtn.setUserObject( "" );
662 case CONFIDENCE_VALUE:
663 double confidence = Confidence.CONFIDENCE_DEFAULT_VALUE;
664 if ( !ForesterUtil.isEmpty( value ) ) {
666 confidence = ForesterUtil.parseDouble( value );
668 catch ( final ParseException e ) {
669 JOptionPane.showMessageDialog( this,
670 "failed to parse confidence value from: " + value,
672 JOptionPane.ERROR_MESSAGE );
673 mtn.setUserObject( "" );
677 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
678 throw new FailedConditionCheckException();
680 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
681 if ( confidence >= 0 ) {
682 getMyNode().getBranchData().getConfidences().add( new Confidence( confidence, "unknown" ) );
686 final String type = getMyNode().getBranchData().getConfidences().get( number ).getType();
687 getMyNode().getBranchData().getConfidences().set( number, new Confidence( confidence, type ) );
690 case CONFIDENCE_TYPE:
691 if ( getMyNode().getBranchData().getConfidences().size() < number ) {
692 throw new FailedConditionCheckException();
694 else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
695 if ( !ForesterUtil.isEmpty( value ) ) {
696 getMyNode().getBranchData().getConfidences().add( new Confidence( 0, value ) );
700 final double v = getMyNode().getBranchData().getConfidences().get( number ).getValue();
701 getMyNode().getBranchData().getConfidences().set( number, new Confidence( v, value ) );
705 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
707 getMyNode().getNodeData().getTaxonomy().setTaxonomyCode( value );
709 catch ( final PhyloXmlDataFormatException e ) {
710 formatError( mtn, e );
714 case TAXONOMY_SCIENTIFIC_NAME:
715 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
716 getMyNode().getNodeData().getTaxonomy().setScientificName( value );
718 case TAXONOMY_COMMON_NAME:
719 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
720 getMyNode().getNodeData().getTaxonomy().setCommonName( value );
723 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
725 getMyNode().getNodeData().getTaxonomy().setRank( value.toLowerCase() );
727 catch ( final PhyloXmlDataFormatException e ) {
728 formatError( mtn, e );
732 case TAXONOMY_AUTHORITY:
733 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
734 getMyNode().getNodeData().getTaxonomy().setAuthority( value );
738 if ( !ForesterUtil.isEmpty( value ) ) {
740 uri = new Uri( new URL( value ).toURI() );
742 catch ( final Exception e ) {
743 JOptionPane.showMessageDialog( this,
744 "failed to parse URL from: " + value,
746 JOptionPane.ERROR_MESSAGE );
747 mtn.setUserObject( "" );
751 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
753 addUri( mtn, uri, number, getMyNode().getNodeData().getTaxonomy() );
756 case TAXONOMY_SYNONYM:
757 if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() < number ) {
758 throw new FailedConditionCheckException();
760 else if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() == number ) {
761 if ( !ForesterUtil.isEmpty( value ) ) {
762 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
763 getMyNode().getNodeData().getTaxonomy().getSynonyms().add( value );
767 getMyNode().getNodeData().getTaxonomy().getSynonyms().set( number, value );
770 case TAXONOMY_ID_VALUE:
771 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
772 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
773 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value ) );
776 final String provider = getMyNode().getNodeData().getTaxonomy().getIdentifier().getProvider();
777 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value, provider ) );
780 case TAXONOMY_ID_PROVIDER:
781 ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
782 if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
783 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( "", value ) );
786 final String v = getMyNode().getNodeData().getTaxonomy().getIdentifier().getValue();
787 getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( v, value ) );
791 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
792 getMyNode().getNodeData().getSequence().setLocation( value );
795 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
796 getMyNode().getNodeData().getSequence().setMolecularSequence( value );
799 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
800 getMyNode().getNodeData().getSequence().setName( value );
803 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
805 getMyNode().getNodeData().getSequence().setSymbol( value );
807 catch ( final PhyloXmlDataFormatException e ) {
808 formatError( mtn, e );
813 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
815 getMyNode().getNodeData().getSequence().setType( value.toLowerCase() );
817 catch ( final PhyloXmlDataFormatException e ) {
818 formatError( mtn, e );
823 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
824 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
825 getMyNode().getNodeData().getSequence().setAccession( new Accession( "", value ) );
828 final String v = getMyNode().getNodeData().getSequence().getAccession().getValue();
829 getMyNode().getNodeData().getSequence().setAccession( new Accession( v, value ) );
833 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
834 if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
835 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, "" ) );
838 final String source = getMyNode().getNodeData().getSequence().getAccession().getSource();
839 getMyNode().getNodeData().getSequence().setAccession( new Accession( value, source ) );
844 if ( !ForesterUtil.isEmpty( value ) ) {
846 uri = new Uri( new URL( value ).toURI() );
848 catch ( final Exception e ) {
849 JOptionPane.showMessageDialog( this,
850 "failed to parse URL from: " + value,
852 JOptionPane.ERROR_MESSAGE );
853 mtn.setUserObject( "" );
857 ForesterUtil.ensurePresenceOfSequence( getMyNode() );
859 addUri( mtn, uri, number, getMyNode().getNodeData().getSequence() );
862 case LIT_REFERENCE_DESC:
863 if ( !getMyNode().getNodeData().isHasReference() ) {
864 getMyNode().getNodeData().setReference( new Reference( "" ) );
866 getMyNode().getNodeData().getReference().setValue( value );
868 case LIT_REFERENCE_DOI:
869 if ( !getMyNode().getNodeData().isHasReference() ) {
870 getMyNode().getNodeData().setReference( new Reference( "" ) );
873 getMyNode().getNodeData().getReference().setDoi( value );
875 catch ( final PhyloXmlDataFormatException e ) {
876 formatError( mtn, e );
880 case EVENTS_DUPLICATIONS:
881 if ( !getMyNode().getNodeData().isHasEvent() ) {
882 getMyNode().getNodeData().setEvent( new Event() );
884 getMyNode().getNodeData().getEvent().setDuplications( parsePositiveInt( mtn, value ) );
886 case EVENTS_SPECIATIONS:
887 if ( !getMyNode().getNodeData().isHasEvent() ) {
888 getMyNode().getNodeData().setEvent( new Event() );
890 getMyNode().getNodeData().getEvent().setSpeciations( parsePositiveInt( mtn, value ) );
892 case EVENTS_GENE_LOSSES:
893 if ( !getMyNode().getNodeData().isHasEvent() ) {
894 getMyNode().getNodeData().setEvent( new Event() );
896 getMyNode().getNodeData().getEvent().setGeneLosses( parsePositiveInt( mtn, value ) );
898 case DATE_DESCRIPTION:
899 ForesterUtil.ensurePresenceOfDate( getMyNode() );
900 getMyNode().getNodeData().getDate().setDesc( value );
903 ForesterUtil.ensurePresenceOfDate( getMyNode() );
904 getMyNode().getNodeData().getDate().setMax( parseBigDecimal( mtn, value ) );
907 ForesterUtil.ensurePresenceOfDate( getMyNode() );
908 getMyNode().getNodeData().getDate().setMin( parseBigDecimal( mtn, value ) );
911 ForesterUtil.ensurePresenceOfDate( getMyNode() );
912 getMyNode().getNodeData().getDate().setUnit( value );
915 ForesterUtil.ensurePresenceOfDate( getMyNode() );
916 getMyNode().getNodeData().getDate().setValue( parseBigDecimal( mtn, value ) );
919 final BigDecimal new_value = parseBigDecimal( mtn, value );
920 if ( new_value != null ) {
921 final List<Point> ps = obtainPoints();
922 final Point p = ps.get( 0 );
923 final Point p_new = new Point( p.getGeodeticDatum(),
927 ForesterUtil.isEmpty( p.getAltiudeUnit() ) ? "?"
928 : p.getAltiudeUnit() );
934 ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
935 final Distribution d = getMyNode().getNodeData().getDistribution();
936 getMyNode().getNodeData().setDistribution( new Distribution( value, d.getPoints(), d.getPolygons() ) );
939 case DIST_GEODETIC: {
940 if ( !ForesterUtil.isEmpty( value ) ) {
941 final List<Point> ps = obtainPoints();
942 final Point p = ps.get( 0 );
943 final Point p_new = new Point( value,
947 p.getAltiudeUnit() );
952 case DIST_ALT_UNIT: {
953 if ( !ForesterUtil.isEmpty( value ) ) {
954 final List<Point> ps = obtainPoints();
955 final Point p = ps.get( 0 );
956 final Point p_new = new Point( p.getGeodeticDatum(),
966 final BigDecimal new_value = parseBigDecimal( mtn, value );
967 if ( new_value != null ) {
968 final List<Point> ps = obtainPoints();
969 final Point p = ps.get( 0 );
970 final Point p_new = new Point( p.getGeodeticDatum(),
974 p.getAltiudeUnit() );
980 final BigDecimal new_value = parseBigDecimal( mtn, value );
981 if ( new_value != null ) {
982 final List<Point> ps = obtainPoints();
983 final Point p = ps.get( 0 );
984 final Point p_new = new Point( p.getGeodeticDatum(),
988 p.getAltiudeUnit() );
994 throw new IllegalArgumentException( "unknown: " + tag );
996 getJTree().repaint();
997 getTreePanel().setEdited( true );
998 getTreePanel().repaint();
1001 private void addUri( final DefaultMutableTreeNode mtn, final Uri uri, final int number, final MultipleUris mu ) {
1002 if ( uri != null ) {
1003 if ( mu.getUris() == null ) {
1004 mu.setUris( new ArrayList<Uri>() );
1007 if ( ( uri != null ) && ( mu.getUris() == null ) ) {
1008 mu.setUris( new ArrayList<Uri>() );
1010 if ( ( uri != null ) && ( mu.getUris().size() == number ) ) {
1011 mu.getUris().add( uri );
1013 if ( ( mu.getUris() != null ) && ( mu.getUris().size() != number ) ) {
1014 mu.getUris().set( number, uri );
1016 final ImageLoader il = new ImageLoader( getTreePanel() );
1017 new Thread( il ).start();
1020 private enum PHYLOXML_TAG {
1024 TAXONOMY_SCIENTIFIC_NAME,
1026 TAXONOMY_COMMON_NAME,
1042 TAXONOMY_ID_PROVIDER,
1049 EVENTS_DUPLICATIONS,
1060 private class TagNumber {
1062 final private PHYLOXML_TAG _tag;
1063 final private int _number;
1065 TagNumber( final PHYLOXML_TAG tag, final int number ) {
1074 PHYLOXML_TAG getTag() {
1079 public String toString() {
1080 return getTag() + "_" + getNumber();