6 use CXGN
::Phylo
::Configuration
;
8 package CXGN
::Phylo
::Tree_browser
;
12 my $directives = shift;
15 my $self = bless $args, $class;
17 # set the default using the setter functions
19 $self->set_tree(undef);
20 #want this to work outside of mod_perl: (ccarpita)
21 unless($directives->{no_apache
}){
22 $self->set_temp_file(undef);
24 $self->set_temp_url(undef);
25 $self->set_tree_string(undef);
26 $self->set_temp_dir(undef);
29 # build the function hash
31 $self->add_code_table("r", "function_rotate_node", 2);
32 $self->add_code_table("h", "function_hide_node", 2);
33 $self->add_code_table("s", "function_prune_to_subtree", 1);
34 $self->add_code_table("t", "function_reset_root", 1);
39 =head2 function get_tree()
54 =head2 function set_tree
69 sub create_temp_file
{
72 my $tempdir = $self->get_temp_dir();
73 #print STDERR "TEMPDIR: $tempdir\n";
74 my ($tempfh, $tempfile) = File
::Temp
::tempfile
("tree-XXXXXX", DIR
=>$tempdir);
75 print $tempfh $self->get_tree_string();
78 my $temp_url = $tempfile;
79 $temp_url =~ s/.*(tempfiles.*$)/$1/;
81 $temp_url = "/documents/$temp_url";
83 $self->set_temp_url($temp_url);
84 $self->set_temp_file($tempfile);
86 return ($tempfile, $temp_url);
94 if( open my $fh, $self->get_temp_file() ) {
102 $self->set_tree_string($file_contents);
106 =head2 function get_temp_url()
118 if (!$self->{temp_url
}) {
119 my $url = $self->get_temp_file();
120 $url = File
::Basename
::basename
($url);
121 $url = "/documents/tempfiles/tree_browser/$url";
122 $self->{temp_url
}=$url;
124 return $self->{temp_url
};
127 =head2 function set_temp_url()
139 $self->{temp_url
}=shift;
142 =head2 function get_temp_file()
155 my $tf = $self->{temp_file
};
157 #print STDERR "in Tree_browser::get_temp_file(), temp_file: [", $tf, "]\n";
159 return $self->{temp_file
};
162 =head2 function set_temp_file()
164 Synopsis: $browser->set_temp_file($filename);
165 Arguments: a valid filename
167 Side effects: tries to read the tree string from $filename
168 and sets it using set_tree_string()
175 $self->{temp_file
}=shift;
176 if (!$self->get_tree_string()) { $self->read_temp_file(); }
179 =head2 function get_tree_string()
189 sub get_tree_string
{
191 return $self->{tree_string
};
194 =head2 function set_tree_string()
204 sub set_tree_string
{
206 $self->{tree_string
}=shift;
209 =head2 function get_temp_dir
213 Returns: a temp directory. If the directory was not set using
214 set_temp_dir(), it tries to come up with a good guess.
215 Side effects: the temp_dir property is used to write the temporary files
216 to. If it is not correct, the browser won\'t work.
224 if (!exists($self->{temp_dir
}) || !$self->{temp_dir
}) {
225 $self->{temp_dir
} = CXGN
::Phylo
::Configuration
->new()->get_temp_dir();
227 return $self->{temp_dir
};
230 =head2 function set_temp_dir
242 $self->{temp_dir
}=shift;
245 =head2 function recursive_manage_labels()
255 sub recursive_manage_labels
{
259 # check the shortest branch length on this node
261 my $shortest = 1e200
;
262 foreach my $c ($node->get_children()) {
263 if ($c->get_branch_length() < $shortest) {
264 $shortest=$c->get_branch_length();
268 my $scaling_factor = $self->get_tree()->get_layout()->get_horizontal_scaling_factor();
269 if ( ($shortest * $scaling_factor) > (length($node->get_name())*5) ) {
270 $node->get_label()->set_hidden(0);
272 elsif ($node->get_hilited()) {
273 $node->get_label()->set_hidden(0);
275 elsif ($node->is_leaf()) {
276 $node->get_label()->set_hidden(0);
278 elsif ($node->get_label()->get_hilite()) {
279 $node->get_label()->set_hidden(0);
281 elsif ($node->get_hidden()) {
282 $node->get_label()->set_hidden(0);
285 $node->get_label()->set_hidden(1);
288 foreach my $c ($node->get_children()) {
289 $self->recursive_manage_labels($c);
297 =head2 function get_hilite
301 Returns: the node key (NOT a node object) of the hilited node
309 return $self->{hilite
};
312 =head2 function set_hilite
326 # if hilite is undefined, everything will be hilited,
327 # which is not the desired behavior.
329 if (!defined($hilite)) { $hilite=""; }
331 $self->{hilite
}=$hilite;
334 sub get_node_operations
{
336 if (!exists($self->{node_operations
})) { @
{$self->{node_operations
}}=(); }
337 return @
{$self->{node_operations
}};
340 =head2 function toggle_node_operation()
342 Synopsis: $a_tree_browser->toggle_node_operation($the_operation);
343 Arguments: A node operation.
345 Side effects: Removes the operation from the node_operation list, if initially present,
346 and pushes in onto the list if not initially present.
347 Description: node operations have to be played back in the same order
348 as they were generated by the user. The node operations
349 are therefore stored in an array. (in a first version,
350 they were stored in a hash which caused play back problems).
354 sub toggle_node_operation
{
356 my $operation = shift;
357 if (!exists($self->{node_operations
})) { #initialize node operations array to empty list
358 @
{$self->{node_operations
}}=();
361 for (my $i=0; $i<@
{$self->{node_operations
}}; $i++) { # loop over node operations in the list
362 if (${$self->{node_operations
}}[$i] =~ /^$operation$/i) {
364 splice @
{$self->{node_operations
}}, $i, 1;
368 push @
{$self->{node_operations
}}, $operation;
375 my $function = shift;
376 my $priority = shift;
377 ${$self->{op_code
}}{$code}=$function;
378 ${$self->{op_code_priority
}}{$code}=$priority;
386 if (exists(${$self->{op_code
}}{$code})) {
387 return (${$self->{op_code
}}{$code}, ${$self->{op_code_priority
}}{$code});
390 print STDERR
"tree_browser.pm: $code is not a recognized function.\n";
395 =head2 function play_back_operations()
397 Synopsis: $browser->play_back_operations();
400 Side effects: takes the operations as set by set_node_operations() and
401 executes the commands on the tree data structure.
402 It is important that the operations are played back in the
403 exact order they were initiated by the user.
408 sub play_back_operations
{
411 my @node_operations = $self->get_node_operations();
412 #print STDERR "Operations: ".(join "|", @node_operations)."\n";
414 foreach my $priority (1, 2) {
415 foreach my $operation (@node_operations) {
416 my $code=""; my $node_key=0;
417 if ($operation =~ m/([a-z]+)(\d+)/i) {
422 #print STDERR "OPERATION: $code ON NODE $node_key\n";
423 my $node = $self->get_tree()->get_node($node_key);
425 if ($code && !$self->get_code_table($code)) { print STDERR
"Operation $code is undefined!\n"; next; }
426 my ($operation_sub, $operation_priority) = $self->get_code_table($code);
427 #print STDERR "Executing function $code on node $node_key\n";
429 if ($priority == $operation_priority) {
430 $self->$operation_sub($node);
436 # recalculate tree parameters
438 $self->get_tree()->regenerate_node_hash($self->get_tree()->get_root());
439 $self->get_tree()->get_root()->calculate_distances_from_root();
441 $self->get_tree()->calculate_leaf_list();
442 $self->get_tree()->get_root()->recursive_propagate_properties();
446 sub function_rotate_node
{
449 #print STDERR "sub function_rotate_node: Rotating node: ".$node->get_node_key()."\n";
450 $node->rotate_node();
453 sub function_hide_node
{
456 $node->set_hidden(1);
459 sub function_prune_to_subtree
{
462 $self->get_tree->prune_to_subtree($node);
465 sub function_reset_root
{
468 $self->get_tree()->reset_root($node);