ARB
TreeCallbacks.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : TreeCallbacks.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "TreeCallbacks.hxx"
12 
13 #include <aw_color_groups.hxx>
14 #include <aw_awars.hxx>
15 #include <aw_advice.hxx>
16 #include <aw_msg.hxx>
17 #include <aw_root.hxx>
18 #include <mode_text.h>
19 
20 #include <cctype>
21 
22 using namespace AW;
23 
24 // AISC_MKPT_PROMOTE:#ifndef TREEDISPLAY_HXX
25 // AISC_MKPT_PROMOTE:#include <TreeDisplay.hxx>
26 // AISC_MKPT_PROMOTE:#endif
27 
29  const char *text;
30 
31  switch (mode) {
32  case AWT_MODE_ZOOM: text = MODE_TEXT_STANDARD_ZOOMMODE(); break;
33  case AWT_MODE_EMPTY: text = MODE_TEXT_PLACEHOLDER(); break;
34 
35  case AWT_MODE_SELECT: text = MODE_TEXT_1BUTTON("SELECT", "select species or open/close group"); break;
36  case AWT_MODE_INFO: text = MODE_TEXT_1BUTTON("INFO", "click for info"); break;
37  case AWT_MODE_WWW: text = MODE_TEXT_1BUTTON("WEB", "Launch node dependent URL (see <Properties/WWW...>)"); break;
38 
39  case AWT_MODE_SWAP: text= MODE_TEXT_2BUTTONS("SWAP", "swap child branches", "flip whole subtree"); break;
40  case AWT_MODE_MARK: text= MODE_TEXT_2BUTTONS("MARK", "mark subtree", "unmark subtree"); break;
41  case AWT_MODE_GROUP: text= MODE_TEXT_2BUTTONS("GROUP", "fold/unfold group", "create/rename/destroy group"); break;
42  case AWT_MODE_NNI: text= MODE_TEXT_2BUTTONS("OPTI(NNI)", "once", "repeated"); break;
43  case AWT_MODE_KERNINGHAN: text= MODE_TEXT_2BUTTONS("OPTI(KL)", "once", "repeated"); break;
44  case AWT_MODE_OPTIMIZE: text= MODE_TEXT_2BUTTONS("OPTI(NNI&KL)", "once", "repeated"); break;
45  case AWT_MODE_SETROOT: text= MODE_TEXT_2BUTTONS("REROOT", "set root to clicked branch", "search optimal root"); break;
46 
47  case AWT_MODE_ROTATE: text = MODE_TEXT_1BUTTON_KEYS("ROTATE", "drag branch to rotate", KEYINFO_ABORT_AND_RESET); break;
48  case AWT_MODE_SPREAD: text = MODE_TEXT_1BUTTON_KEYS("SPREAD", "drag branch to spread subtree", KEYINFO_ABORT_AND_RESET); break;
49 
50  case AWT_MODE_LENGTH: text = MODE_TEXT_2BUTTONS_KEYS("LENGTH", "drag branch/ruler", "use discrete lengths", KEYINFO_ABORT_AND_RESET); break;
51  case AWT_MODE_MULTIFURC: text = MODE_TEXT_2BUTTONS_KEYS("MULTIFURC", "drag branch", "use discrete lengths", KEYINFO_ABORT_AND_RESET); break;
52  case AWT_MODE_LINE: text = MODE_TEXT_2BUTTONS_KEYS("LINE", "drag branch/ruler", "whole subtree", KEYINFO_ABORT_AND_RESET); break;
53  case AWT_MODE_MOVE: text = MODE_TEXT_2BUTTONS_KEYS("MOVE", "drag branch/ruler", "move groupinfo only", KEYINFO_ABORT); break;
54  case AWT_MODE_LZOOM: text = MODE_TEXT_2BUTTONS_KEYS("LOGICAL ZOOM", "show only subtree", "go up one step", KEYINFO_RESET); break;
55 
56  default: text = no_mode_text_defined(); break;
57  }
58 
59  td_assert(strlen(text) < AWAR_FOOTER_MAX_LEN); // text too long!
60 
61  ntw->awr->awar(AWAR_FOOTER)->write_string(text);
62  ntw->set_mode(mode);
63 }
64 
65 // ---------------------------------------
66 // Basic mark/unmark callbacks :
67 
70 
72  long count = GB_number_of_marked_subentries(gb_species_data);
73 
75 
76  char buf[256];
77  switch (count) {
78  case 0: strcpy(buf, "There are NO marked species"); break;
79  case 1: strcpy(buf, "There is 1 marked species"); break;
80  default: sprintf(buf, "There are %li marked species", count); break;
81  }
82  strcat(buf, ". (The number of species is displayed in the top area as well)");
83  aw_message(buf);
84 }
85 
86 static bool species_has_alignment(GBDATA *gb_species, void *cd_use) {
87  return GBT_find_sequence(gb_species, (const char*)cd_use);
88 }
89 
90 static bool sequence_is_partial(GBDATA *gb_species, void *cd_partial) {
91  long wanted = (long)cd_partial;
92  td_assert(wanted == 0 || wanted == 1);
93  bool partial = GBT_is_partial(gb_species, 0, false);
94 
95  return partial == wanted;
96 }
97 
98 #define MARK_MODE_LOWER_BITS (1|2)
99 #define MARK_MODE_UPPER_BITS (4|8|16)
100 
102  // Bits 0 and 1 of mark_mode:
103  //
104  // mark_mode&3 == 0 -> unmark
105  // mark_mode&3 == 1 -> mark
106  // mark_mode&3 == 2 -> toggle mark
107  //
108  // Bits 2 .. 4 of mark_mode:
109  //
110  // mark_mode&12 == 4 -> affect only full sequences
111  // mark_mode&12 == 8 -> affect only partial sequences
112  // mark_mode&12 == 16 -> affect only species with data in current alignment
113  // else -> affect all sequences
114 
115  AWT_auto_refresh allowed_on(ntw);
116  GB_transaction ta(ntw->gb_main);
117 
118  switch (mark_mode&MARK_MODE_UPPER_BITS) {
119  case 0: // all sequences
120  GBT_mark_all(ntw->gb_main, mark_mode&MARK_MODE_LOWER_BITS);
121  break;
122  case 4: // full sequences only
123  GBT_mark_all_that(ntw->gb_main, mark_mode&MARK_MODE_LOWER_BITS, sequence_is_partial, (void*)NULp);
124  break;
125  case 8: // partial sequences only
126  GBT_mark_all_that(ntw->gb_main, mark_mode&MARK_MODE_LOWER_BITS, sequence_is_partial, (void*)1);
127  break;
128  case 16: { // species with data in alignment only
129  char *ali = GBT_get_default_alignment(ntw->gb_main);
130  if (ali) GBT_mark_all_that(ntw->gb_main, mark_mode&MARK_MODE_LOWER_BITS, species_has_alignment, (void*)ali);
131  free(ali);
132  break;
133  }
134  default:
135  td_assert(0); // illegal mode
136  break;
137  }
138 
139  ntw->request_structure_update(); // includes refresh etc
140 }
141 
142 static void mark_tree_cb(UNFIXED, TREE_canvas *ntw, int mark_mode) {
143  GB_transaction ta(ntw->gb_main);
144  AWT_auto_refresh allowed_on(ntw);
145  AWT_graphic_tree *gtree = AWT_TREE(ntw);
146  AP_tree *tree_root = gtree->get_root_node();
147 
148  switch (mark_mode&MARK_MODE_UPPER_BITS) {
149  case 0: // all sequences
150  gtree->mark_species_in_tree(tree_root, mark_mode&MARK_MODE_LOWER_BITS);
151  break;
152  case 4: // full sequences only
153  gtree->mark_species_in_tree_that(tree_root, mark_mode&MARK_MODE_LOWER_BITS, sequence_is_partial, (void*)NULp);
154  break;
155  case 8: // partial sequences only
156  gtree->mark_species_in_tree_that(tree_root, mark_mode&MARK_MODE_LOWER_BITS, sequence_is_partial, (void*)1);
157  break;
158  case 16: { // species with data in alignment only
159  char *ali = GBT_get_default_alignment(ntw->gb_main);
160  if (ali) gtree->mark_species_in_tree_that(tree_root, mark_mode&MARK_MODE_LOWER_BITS, species_has_alignment, (void*)ali);
161  free(ali);
162  break;
163  }
164  default:
165  td_assert(0); // illegal mode
166  break;
167  }
169 }
170 
173  char *ali; // current alignment (only if mark_mode_upper_bits == 16)
175 };
176 
177 static bool are_not_in_tree(GBDATA *gb_species, void *cb_data) {
178  struct mark_nontree_cb_data *data = (mark_nontree_cb_data*)cb_data;
179  bool mark_me = false;
180 
181  if (GBS_read_hash(data->hash, GBT_get_name_or_description(gb_species)) == (long)gb_species) { // species is not in tree!
182  switch (data->mark_mode_upper_bits) {
183  case 0: // all sequences
184  mark_me = true;
185  break;
186  case 4: // full sequences only
187  mark_me = sequence_is_partial(gb_species, (void*)NULp);
188  break;
189  case 8: // partial sequences only
190  mark_me = sequence_is_partial(gb_species, (void*)1);
191  break;
192  case 16: // species with data in alignment only
193  mark_me = species_has_alignment(gb_species, data->ali);
194  break;
195  default:
196  td_assert(0); // illegal mode
197  break;
198  }
199  }
200 
201  return mark_me;
202 }
203 
204 static void mark_nontree_cb(UNFIXED, TREE_canvas *ntw, int mark_mode) {
205  AWT_graphic_tree *gtree = AWT_TREE(ntw);
206  GB_transaction ta(ntw->gb_main);
207  struct mark_nontree_cb_data cd;
208  AWT_auto_refresh allowed_on(ntw);
209 
210  if ((mark_mode&MARK_MODE_LOWER_BITS) == 0) { // unmark is much faster
211  cd.hash = GBT_create_marked_species_hash(ntw->gb_main); // because it only hashes marked species
212  }
213  else {
214  cd.hash = GBT_create_species_hash(ntw->gb_main); // for mark we have to hash ALL species
215  }
216 
218 
221 
222  GBT_mark_all_that(ntw->gb_main, mark_mode&MARK_MODE_LOWER_BITS, are_not_in_tree, (void*)&cd);
223 
224  free(cd.ali);
225 
226  ntw->request_refresh(); // does only affect display of NDS list (if tree shown -> never changes; i.e. no structure update needed)
227 }
228 
229 static char *create_mark_menu_entry(const char *attrib, const char *entry_template) {
230  char *entry = NULp;
231  if (attrib) {
232  bool append = attrib[0] == '-'; // if attrib starts with '-' then append (otherwise prepend)
233  if (append) ++attrib; // skip '-'
234 
235  if (append) {
236  char *spaced_attrib = GBS_global_string_copy(" %s", attrib);
237  entry = GBS_global_string_copy(entry_template, "", spaced_attrib);
238  free(spaced_attrib);
239  }
240  else {
241  char *spaced_attrib = GBS_global_string_copy("%s ", attrib);
242  entry = GBS_global_string_copy(entry_template, spaced_attrib, "");
243 
244  if (islower(entry[0])) entry[0] = toupper(entry[0]); // Caps prepended lowercase 'attrib'
245 
246  free(spaced_attrib);
247  }
248  }
249  else {
250  entry = GBS_global_string_copy(entry_template, "", "");
251  }
252  return entry;
253 }
254 static char *create_mark_menu_id(const char *attrib, const char *id_suffix) {
255  char *id = NULp;
256  if (attrib) {
257  id = GBS_global_string_copy("%s_%s", attrib[0] == '-' ? attrib+1 : attrib, id_suffix);
258  }
259  else {
260  id = strdup(id_suffix);
261  }
262  return id;
263 }
264 
265 static void insert_mark_topic(AW_window_menu_modes *awm, AW_active mask, const char *attrib, const char *id_suffix, const char *entry_template,
266  const char *hotkey, const char *helpfile, const WindowCallback& wcb)
267 {
268  char *entry = create_mark_menu_entry(attrib, entry_template);
269  char *id = create_mark_menu_id(attrib, id_suffix);
270 
271  awm->insert_menu_topic(id, entry, hotkey, helpfile, mask, wcb);
272 
273  free(id);
274  free(entry);
275 }
276 
277 static void insert_mark_topics(AW_window_menu_modes *awm, AW_active mask, TREE_canvas *ntw, int affect, const char *attrib) {
278  td_assert(affect == (affect&MARK_MODE_UPPER_BITS)); // only bits 2 .. 4 are allowed
279 
280  insert_mark_topic(awm, mask, attrib, "mark_all", "Mark all %sSpecies%s", "M", "sp_mark.hlp", makeWindowCallback(NT_mark_all_cb, ntw, 1+affect));
281  insert_mark_topic(awm, mask, attrib, "unmark_all", "Unmark all %sSpecies%s", "U", "sp_mark.hlp", makeWindowCallback(NT_mark_all_cb, ntw, 0+affect));
282  insert_mark_topic(awm, mask, attrib, "swap_marked", "Invert marks of all %sSpecies%s", "I", "sp_mark.hlp", makeWindowCallback(NT_mark_all_cb, ntw, 2+affect));
283  awm->sep______________();
284 
285  char *label = create_mark_menu_entry(attrib, "%sSpecies%s in Tree");
286 
287  awm->insert_sub_menu(label, "T");
288  insert_mark_topic(awm, mask, attrib, "mark_tree", "Mark %sSpecies%s in Tree", "M", "sp_mark.hlp", makeWindowCallback(mark_tree_cb, ntw, 1+affect));
289  insert_mark_topic(awm, mask, attrib, "unmark_tree", "Unmark %sSpecies%s in Tree", "U", "sp_mark.hlp", makeWindowCallback(mark_tree_cb, ntw, 0+affect));
290  insert_mark_topic(awm, mask, attrib, "swap_marked_tree", "Invert marks of %sSpecies%s in Tree", "I", "sp_mark.hlp", makeWindowCallback(mark_tree_cb, ntw, 2+affect));
291  awm->close_sub_menu();
292 
293  freeset(label, create_mark_menu_entry(attrib, "%sSpecies%s NOT in Tree"));
294 
295  awm->insert_sub_menu(label, "N");
296  insert_mark_topic(awm, mask, attrib, "mark_nontree", "Mark %sSpecies%s NOT in Tree", "M", "sp_mark.hlp", makeWindowCallback(mark_nontree_cb, ntw, 1+affect));
297  insert_mark_topic(awm, mask, attrib, "unmark_nontree", "Unmark %sSpecies%s NOT in Tree", "U", "sp_mark.hlp", makeWindowCallback(mark_nontree_cb, ntw, 0+affect));
298  insert_mark_topic(awm, mask, attrib, "swap_marked_nontree", "Invert marks of %sSpecies%s NOT in Tree", "I", "sp_mark.hlp", makeWindowCallback(mark_nontree_cb, ntw, 2+affect));
299  awm->close_sub_menu();
300 
301  free(label);
302 }
303 
304 void NT_insert_mark_submenus(AW_window_menu_modes *awm, TREE_canvas *ntw, int insert_as_submenu) {
305  if (insert_as_submenu) {
306  awm->insert_sub_menu("Mark species", "M");
307  }
308 
309  {
310  awm->insert_menu_topic("count_marked", "Count Marked Species", "C", "sp_count_mrk.hlp", AWM_ALL, makeWindowCallback(count_mark_all_cb, ntw));
311  awm->sep______________();
312  insert_mark_topics(awm, AWM_ALL, ntw, 0, NULp);
313  awm->sep______________();
314 
315  awm->insert_sub_menu("Complete sequences", "o");
316  insert_mark_topics(awm, AWM_EXP, ntw, 4, "complete");
317  awm->close_sub_menu();
318 
319  awm->insert_sub_menu("Partial sequences", "P");
320  insert_mark_topics(awm, AWM_EXP, ntw, 8, "partial");
321  awm->close_sub_menu();
322 
323  awm->insert_sub_menu("Current Alignment", "A");
324  insert_mark_topics(awm, AWM_EXP, ntw, 16, "-with data");
325  awm->close_sub_menu();
326  }
327 
328  if (insert_as_submenu) {
329  awm->close_sub_menu();
330  }
331 }
332 
333 // ----------------------------------------
334 // Automated collapse/expand tree
335 
336 static void group_and_refold_tree(TREE_canvas *ntw, CollapseMode mode, int color_group) {
337  GB_transaction ta(ntw->gb_main);
338  AWT_auto_refresh allowed_on(ntw);
339  AWT_graphic_tree *agt = AWT_TREE(ntw);
340  AP_tree *root_node = agt->get_root_node();
341 
342  agt->group_tree(root_node, mode, color_group);
343 
344  agt->fast_sync_changed_folding(root_node);
345 }
346 
352 
353 static void expand_color_cb(UNFIXED, TREE_canvas *ntw, int colornum) { group_and_refold_tree(ntw, EXPAND_COLOR, colornum); }
354 
356  const int MAXLABEL = 31;
357  const int MAXENTRY = AW_COLOR_GROUP_NAME_LEN+10;
358 
359  td_assert(ntree_canvas);
360 
361  awm->insert_sub_menu("Expand color ...", "o");
362 
363  char label_buf[MAXLABEL+1];
364  char entry_buf[MAXENTRY+1];
365  char hotkey[] = "x";
366  const char *hotkeys = "AN1234567890BC"+1;
367 
368  for (int i = -1; i <= AW_COLOR_GROUPS; ++i) {
369  hotkey[0] = hotkeys[i];
370  if (hotkey[0] == ' ') hotkey[0] = 0;
371 
372  if (i) {
373  if (i<0) {
374  strcpy(label_buf, "tree_group_not_any_color");
375  strcpy(entry_buf, "Any color group");
376  }
377  else {
378  sprintf(label_buf, "tree_group_not_color_%i", i);
379 
380  char *color_group_name = AW_get_color_group_name(awm->get_root(), i);
381  size_t len = strlen(color_group_name);
382  if (len>AW_COLOR_GROUP_NAME_LEN) {
383  color_group_name[AW_COLOR_GROUP_NAME_LEN] = 0; // truncate overlong colorgroup names
384  }
385  sprintf(entry_buf, "%s group '%s'", hotkey, color_group_name);
386  free(color_group_name);
387  }
388  }
389  else {
390  strcpy(label_buf, "tree_group_not_no_color");
391  strcpy(entry_buf, "No color group");
392  }
393 
394  awm->insert_menu_topic(awm->local_id(label_buf), entry_buf, hotkey, "tree_group.hlp", AWM_ALL, makeWindowCallback(expand_color_cb, ntree_canvas, i));
395  }
396 
397  awm->close_sub_menu();
398 }
399 
401  awm->insert_sub_menu("Collapse/expand groups", "d");
402  {
403  const char *grouphelp = "tree_group.hlp";
404  awm->insert_menu_topic(awm->local_id("tree_group_all"), "Collapse all", "C", grouphelp, AWM_ALL, makeWindowCallback(collapse_all_cb, ntw));
405  awm->insert_menu_topic(awm->local_id("tree_group_term_groups"), "Collapse terminal", "t", grouphelp, AWM_ALL, makeWindowCallback(collapse_terminal_cb, ntw));
406  awm->sep______________();
407  awm->insert_menu_topic(awm->local_id("tree_ungroup_all"), "Expand all", "E", grouphelp, AWM_ALL, makeWindowCallback(expand_all_cb, ntw));
408  awm->insert_menu_topic(awm->local_id("tree_group_not_marked"), "Expand marked", "m", grouphelp, AWM_ALL, makeWindowCallback(NT_expand_marked_cb, ntw));
409  awm->insert_menu_topic(awm->local_id("tree_ungroup_zombies"), "Expand zombies", "z", grouphelp, AWM_ALL, makeWindowCallback(expand_zombies_cb, ntw));
410  awm->sep______________();
412  }
413  awm->close_sub_menu();
414 }
415 
416 // ------------------------
417 // tree sorting :
418 
420  // 'displayed_tree_cb' has to return true if tree was changed and needs to be saved
421 
422  GB_transaction ta(ntw->gb_main);
423  AWT_auto_refresh allowed_on(ntw);
424 
425  GB_ERROR error = NULp;
426  if (displayed_tree_cb(AWT_TREE(ntw)->get_root_node(), error)) {
428  }
429  return error;
430 }
431 
433  GB_transaction ta(ntw->gb_main);
434  AWT_auto_refresh allowed_on(ntw);
435 
436  AWT_TREE(ntw)->reorderTree(order);
438 }
439 
441  GB_transaction ta(ntw->gb_main);
442  AWT_auto_refresh allowed_on(ntw);
443  AWT_graphic_tree *agt = AWT_TREE(ntw);
444 
445  agt->set_logical_root_to(agt->get_root_node());
446  ntw->request_zoom_reset();
447 }
448 
450  GB_transaction ta(ntw->gb_main);
451  AWT_auto_refresh allowed_on(ntw);
452  ntw->request_zoom_reset();
453 }
454 
456  {
457  AWT_auto_refresh allowed_on(ntw);
458  AWT_TREE(ntw)->set_tree_style(style, ntw);
459  ntw->request_zoom_reset();
460  }
462 }
463 
465  NT_set_tree_style(NULp, ntw, AWT_TREE(ntw)->get_tree_style());
466 }
467 
469  GB_transaction ta(ntw->gb_main);
470  AWT_auto_refresh allowed_on(ntw);
471 
472  AP_tree *root_node = AWT_TREE(ntw)->get_root_node();
473  if (root_node) {
474  AWT_TREE(ntw)->get_tree_root()->remove_leafs(mode);
476  }
477  else {
478  aw_message("Got no tree");
479  }
480 }
481 
482 void NT_remove_bootstrap(UNFIXED, TREE_canvas *ntw) { // delete all bootstrap values
483  GB_transaction ta(ntw->gb_main);
484  AWT_auto_refresh allowed_on(ntw);
485 
486  AP_tree *root_node = AWT_TREE(ntw)->get_root_node();
487  if (root_node) {
488  root_node->remove_bootstrap();
490  }
491  else {
492  aw_message("Got no tree");
493  }
494 }
495 
496 void NT_reset_branchlengths(UNFIXED, TREE_canvas *ntw) { // set all branchlengths to tree_defaults::LENGTH
497  GB_transaction ta(ntw->gb_main);
498  AWT_auto_refresh allowed_on(ntw);
499 
500  AP_tree *root_node = AWT_TREE(ntw)->get_root_node();
501  if (root_node) {
502  root_node->reset_branchlengths();
504  }
505  else {
506  aw_message("Got no tree");
507  }
508 }
509 
511  GB_transaction ta(ntw->gb_main);
512  AWT_auto_refresh allowed_on(ntw);
513 
514  TreeNode *tree = AWT_TREE(ntw)->get_root_node();
515  if (tree) {
516  tree->multifurcate_whole_tree(below);
518  }
519  else {
520  aw_message("Got no tree");
521  }
522 }
523 
524 void NT_move_boot_branch(UNFIXED, TREE_canvas *ntw, int direction) { // copy branchlengths to bootstraps (or vice versa)
525  GB_transaction ta(ntw->gb_main);
526  AWT_auto_refresh allowed_on(ntw);
527 
528  AP_tree *root_node = AWT_TREE(ntw)->get_root_node();
529  if (root_node) {
530  if (direction == 0) root_node->bootstrap2branchlen();
531  else root_node->branchlen2bootstrap();
532 
534 
535  char *adviceText = GBS_global_string_copy("Please note, that you just overwrote your existing %s.",
536  direction ? "bootstrap values" : "branchlengths");
537  AW_advice(adviceText, AW_ADVICE_TOGGLE_AND_HELP, NULp, "tbl_boot2len.hlp");
538  free(adviceText);
539  }
540  else {
541  aw_message("Got no tree");
542  }
543 }
544 
545 void NT_scale_tree(UNFIXED, TREE_canvas *ntw) { // scale branchlengths
546  char *answer = aw_input("Enter scale factor", "Scale branchlengths by factor:", "100");
547  if (answer) {
548  double factor = atof(answer);
549  AP_tree *root_node = AWT_TREE(ntw)->get_root_node();
550 
551  if (root_node) {
552  GB_transaction ta(ntw->gb_main);
553  AWT_auto_refresh allowed_on(ntw);
554  root_node->scale_branchlengths(factor);
556  }
557  else {
558  aw_message("Got no tree");
559  }
560  free(answer);
561  }
562 }
563 
565  return DOWNCAST(AP_tree*, t1->ancestor_common_with(t2));
566 }
567 
569  if (jumpType == AP_DONT_JUMP) return;
570 
571  AW_window *aww = ntw->aww;
572  AWT_graphic_tree *gtree = AWT_TREE(ntw);
573 
574  GB_transaction ta(ntw->gb_main);
575  AWT_auto_refresh allowed_on(ntw);
576 
577  AW_root *aw_root = aww->get_root();
578  const char *name = aw_root->awar(AWAR_SPECIES_NAME)->read_char_pntr();
579  GBDATA *gb_group = gtree->get_selected_group().get_group_data();
580 
581  char *msg = NULp;
582  bool verboose = jumpType & AP_JUMP_BE_VERBOOSE;
583 
584  if (name[0] || gb_group) {
585  AP_tree *found = NULp;
586  bool is_tree = is_tree_style(gtree->get_tree_style());
587  bool jump_to_group = gb_group && is_tree; // @@@ prefer group atm
588 
589  if (is_tree) {
590  if (gtree && gtree->get_logical_root()) {
591  if (jump_to_group) {
592  found = gtree->locate_selected_group(gtree->get_logical_root());
593  td_assert(found && found->is_clade());
594  }
595  else {
596  found = gtree->get_logical_root()->findLeafNamed(name);
597  }
598 
599  if (!found && gtree->is_logically_zoomed()) {
600  if (jump_to_group) {
601  found = gtree->locate_selected_group(gtree->get_root_node());
602  }
603  else {
604  found = gtree->get_root_node()->findLeafNamed(name);
605  }
606 
607  if (found) { // species/group is invisible because it is outside logically zoomed tree
608  if (jumpType & AP_JUMP_LOGICAL_UNZOOM) {
609  gtree->set_logical_root_to(common_ancestor(found, gtree->get_logical_root()));
610  ntw->request_resize();
611  }
612  else {
613  if (verboose) {
614  if (jump_to_group) {
615  msg = GBS_global_string_copy("Group '%s' is outside logical zoomed subtree", gtree->get_selected_group().get_name());
616  }
617  else {
618  msg = GBS_global_string_copy("Species '%s' is outside logical zoomed subtree", name);
619  }
620  }
621 
622  found = NULp;
623  }
624  }
625  }
626 
627  if (found && !(jumpType&AP_JUMP_AUTO_UNFOLD) && found->is_inside_folded_group()) {
628  found = NULp; // => just undo auto-unfolding
629  }
630  gtree->auto_unfold(found);
631  }
632  }
633 
634  if (found || !is_tree) {
635  bool is_IRS = gtree->get_tree_style() == AP_TREE_IRS;
636  bool repeat = is_IRS;
637  bool do_jump = true;
638 
639  ntw->sync_DB_model_and_view(false); // sync w/o refresh
640 
641  while (do_jump) {
642  do_jump = false;
643 
646  device->reset();
647  ntw->init_device(device);
648  ntw->gfx->show(device);
649 
650  const AW_screen_area& screen = device->get_area_size();
651 
652  const Position& cursor = jump_to_group ? gtree->get_group_cursor() : gtree->get_cursor();
653  if (are_distinct(Origin, cursor)) {
654  Position S = device->transform(cursor);
655 
656  int scroll_x = 0;
657  int scroll_y = 0;
658 
659  bool do_vcenter = jumpType & AP_JUMP_FORCE_VCENTER;
660  bool do_hcenter = jumpType & AP_JUMP_FORCE_HCENTER;
661 
662  if (!do_vcenter) {
663  if (is_IRS) {
664  // attempt to center IRS tree vertically often fails (too complicated to predict)
665  // => force into center-half of screen to reduce error rate
666  int border = screen.b/10;
667  do_vcenter = S.ypos()<border || S.ypos()>(screen.b-border);
668  }
669  else {
670  do_vcenter = S.ypos()<0.0 || S.ypos()>screen.b; // center if outside viewport
671  }
672  }
673 
674  if (do_vcenter) {
675  scroll_y = (int)(S.ypos() - screen.b*(is_IRS ? .6 : .5)); // position a bit below vertical center for IRS tree
676 
677  if (!scroll_y && (jumpType & AP_JUMP_ALLOW_HCENTER)) { // allow horizontal centering if vertical has no effect
678  do_hcenter = true;
679  }
680  }
681 
682  if (do_hcenter) {
683  scroll_x = (int) (S.xpos() - screen.r * (is_tree ? .5 : .02));
684  }
685  else { // keep visible
686  if (S.xpos()<0.0) {
687  double relPos = 0;
688  switch (gtree->get_tree_style()) {
689  case AP_TREE_NORMAL:
690  case AP_TREE_IRS: relPos = .1; break;
691  case AP_TREE_RADIAL: relPos = .5; break;
692  case AP_LIST_NDS:
693  case AP_LIST_SIMPLE: relPos = .02; break;
694  }
695  scroll_x = (int)(S.xpos() - screen.r * relPos);
696  }
697  else if (S.xpos()>screen.r) {
698  scroll_x = (int)(S.xpos() - screen.r * .5);
699  }
700  }
701 
702  if (scroll_x || scroll_y) ntw->scroll(scroll_x, scroll_y);
703  if (repeat) {
704  // reposition jump in IRS tree (reduces jump failure rate)
705  repeat = false;
706  do_jump = true;
707  }
708  }
709  else {
710  td_assert(!is_tree); // jumped-to position should have been found
711  if (verboose) msg = GBS_global_string_copy("Species '%s' is no member of this list", name);
712  }
713  }
714  }
715 
716  if (!found && is_tree && verboose && !msg) {
717  td_assert(!jump_to_group); // need special handling
718  msg = GBS_global_string_copy("Species '%s' is no member of this %s", name, gtree->get_tree_style() == AP_LIST_NDS ? "list" : "tree");
719  }
720 
721  }
722  else { // select "no species" and "no group"
723  gtree->auto_unfold(NULp); // undo auto-unfolding
724  if (verboose) {
725  msg = strdup("Neither species nor group selected");
726  }
727  }
728 
729  if (gtree) gtree->exports.request_refresh(); // always do refresh to show change of selected species
730 
731  if (msg) {
732  td_assert(verboose);
733  aw_message(msg);
734  free(msg);
735  }
736 }
737 
743  AWT_auto_refresh allowed_on(ntw);
744 
745  bool tree_change = cause == AP_JUMP_REASON_TREE || cause == AP_JUMP_REASON_STYLE;
746 
747  const char *awar_name = tree_change ? AWAR_DTREE_AUTO_JUMP_TREE : AWAR_DTREE_AUTO_JUMP;
748  AW_root *awr = ntw->aww->get_root();
749  AP_tree_jump_type jump_type = AP_tree_jump_type(awr->awar(awar_name)->read_int());
750 
751  if (jump_type == AP_DONT_JUMP) {
752  ntw->request_refresh();
753  }
754  else {
755  bool auto_unfold = awr->awar(AWAR_DTREE_AUTO_UNFOLD)->read_int();
756  if (auto_unfold) jump_type = AP_tree_jump_type(jump_type|AP_JUMP_AUTO_UNFOLD);
757  NT_jump_cb(NULp, ntw, jump_type);
758  }
759 }
760 
761 inline const char *plural(int val) {
762  return "s"+(val == 1);
763 }
764 
765 void NT_reload_tree_event(AW_root *, TREE_canvas *ntw, bool unzoom_and_expose) {
767 
768  {
769  AWT_auto_refresh update(ntw);
770 
771  AWT_graphic_tree *agt = ntw->get_graphic_tree();
772  AP_tree_root *troot = agt->get_tree_root();
773 
774  if (!troot->get_gb_tree()) { // happens at initial startup (=first load) and after a shown tree gets renamed
775  // forget all about old tree
776  agt->forget_auto_unfolded();
777  agt->deselect_group();
778  }
779  else {
780  agt->auto_unfold(NULp); // undo auto-unfolding before tree-change (otherwise temp. unfolding remains saved in DB)
781  }
782  update.suppress_update_and_refresh(); // suppress update (speed)
783  }
784 
785  char *tree_name = ntw->get_awar_tree()->read_string();
786  GB_ERROR error = ntw->gfx->load_from_DB(ntw->gb_main, tree_name);
787  if (error) {
788  aw_message(error);
789  }
790  else {
791  int zombies, duplicates;
792  DOWNCAST(AWT_graphic_tree*, ntw->gfx)->get_zombies_and_duplicates(zombies, duplicates);
793 
794  if (zombies || duplicates) {
795  const char *msg = NULp;
796  if (duplicates) {
797  if (zombies) msg = GBS_global_string("%i zombie%s and %i duplicate%s", zombies, plural(zombies), duplicates, plural(duplicates));
798  else msg = GBS_global_string("%i duplicate%s", duplicates, plural(duplicates));
799  }
800  else {
801  td_assert(zombies);
802  msg = GBS_global_string("%i zombie%s", zombies, plural(zombies));
803  }
804  aw_message(GBS_global_string("%s in '%s'", msg, tree_name));
805  }
806  }
807  free(tree_name);
808  if (unzoom_and_expose) {
809  AWT_auto_refresh allowed_on(ntw);
810  ntw->request_zoom_reset();
811  }
813 }
814 
816  AWT_auto_refresh allowed_on(ntw);
818 }
819 
820 void TREE_GC_changed_cb(GcChange whatChanged, AWT_canvas *ntw) {
821  AWT_auto_refresh allowed_on(ntw);
822 
823  if (whatChanged == GC_COLOR_GROUP_USE_CHANGED) {
824  tree_recompute_cb(NULp, ntw);
825  }
826  else {
827  AWT_GC_changed_cb(whatChanged, ntw);
828  }
829 }
830 
832  if (!tree) return;
833  if (tree->is_leaf() && tree->name) {
834  GBS_write_hash(hash, tree->name, 0); // delete species in hash table
835  }
836  else {
837  NT_remove_species_in_tree_from_hash(tree->get_leftson(), hash);
838  NT_remove_species_in_tree_from_hash(tree->get_rightson(), hash);
839  }
840 }
841 
GB_HASH * GBT_create_marked_species_hash(GBDATA *gb_main)
Definition: adhashtools.cxx:40
AW::Vector transform(const AW::Vector &vec) const
Definition: aw_device.hxx:144
AWT_graphic_tree * get_graphic_tree() const
#define AWT_TREE(ntw)
Definition: TreeDisplay.hxx:77
const char * GB_ERROR
Definition: arb_core.h:25
GB_ERROR NT_with_displayed_tree_do(TREE_canvas *ntw, bool(*displayed_tree_cb)(TreeNode *tree, GB_ERROR &error))
GBDATA * get_group_data() const
Definition: Group.hxx:55
AW_bitset AW_active
Definition: aw_base.hxx:45
AP_tree * get_logical_root()
void bootstrap2branchlen()
Definition: TreeNode.cxx:679
AP_tree_root * get_tree_root()
static void group_and_refold_tree(TREE_canvas *ntw, CollapseMode mode, int color_group)
const char * id
Definition: AliAdmin.cxx:17
virtual GB_ERROR load_from_DB(GBDATA *gb_main, const char *name)=0
static void tree_recompute_cb(UNFIXED, AWT_canvas *ntw)
static void expand_color_cb(UNFIXED, TREE_canvas *ntw, int colornum)
static char * create_mark_menu_id(const char *attrib, const char *id_suffix)
const AW_bitset AW_SIZE
Definition: aw_device.hxx:37
mark_mode
Definition: db_query.cxx:1556
AWT_COMMAND_MODE
Definition: awt_canvas.hxx:25
void request_zoom_reset()
Definition: awt_canvas.hxx:364
void NT_remove_leafs(UNFIXED, TREE_canvas *ntw, AWT_RemoveType mode)
void suppress_update_and_refresh()
Definition: awt_canvas.hxx:430
void nt_mode_event(UNFIXED, TREE_canvas *ntw, AWT_COMMAND_MODE mode)
const AW_screen_area & get_area_size() const
Definition: AW_device.cxx:57
TreeNode * findLeafNamed(const char *wantedName)
Definition: TreeNode.cxx:274
long GBS_write_hash(GB_HASH *hs, const char *key, long val)
Definition: adhash.cxx:457
#define MODE_TEXT_2BUTTONS(modeName, leftInfo, rightInfo)
Definition: mode_text.h:28
AP_tree_jump_reason
void insert_menu_topic(const char *id, const char *name, const char *mnemonic, const char *help_text_, AW_active mask, const WindowCallback &wcb)
Definition: AW_window.cxx:592
void NT_remove_species_in_tree_from_hash(AP_tree *tree, GB_HASH *hash)
void set_logical_root_to(AP_tree *node)
#define AWAR_DTREE_AUTO_JUMP_TREE
Definition: TreeDisplay.hxx:42
AP_tree_jump_type
Definition: TreeDisplay.hxx:87
void NT_mark_all_cb(UNFIXED, TREE_canvas *ntw, int mark_mode)
void request_refresh()
Definition: awt_canvas.hxx:362
#define td_assert(cond)
Definition: Group.hxx:18
void NT_remove_bootstrap(UNFIXED, TREE_canvas *ntw)
void NT_move_boot_branch(UNFIXED, TREE_canvas *ntw, int direction)
long
Definition: AW_awar.cxx:154
bool is_clade() const
Definition: TreeNode.h:439
#define AW_COLOR_GROUPS
void NT_reset_pzoom_cb(UNFIXED, TREE_canvas *ntw)
static void mark_nontree_cb(UNFIXED, TREE_canvas *ntw, int mark_mode)
static void mark_tree_cb(UNFIXED, TREE_canvas *ntw, int mark_mode)
#define MODE_TEXT_PLACEHOLDER()
Definition: mode_text.h:36
static void insert_mark_topic(AW_window_menu_modes *awm, AW_active mask, const char *attrib, const char *id_suffix, const char *entry_template, const char *hotkey, const char *helpfile, const WindowCallback &wcb)
long read_int() const
Definition: AW_awar.cxx:187
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
AW_root * awr
Definition: awt_canvas.hxx:338
void sync_DB_model_and_view(bool perform_refresh)
Definition: AWT_canvas.cxx:515
void AW_advice(const char *message, AW_Advice_Type type, const char *title, const char *corresponding_help)
Show a message box with an advice for the user.
Definition: AW_advice.cxx:160
void forget_auto_unfolded()
void TREE_auto_jump_cb(UNFIXED, TREE_canvas *ntw, AP_tree_jump_reason cause)
static void insert_mark_topics(AW_window_menu_modes *awm, AW_active mask, TREE_canvas *ntw, int affect, const char *attrib)
void NT_reinit_treetype(UNFIXED, TREE_canvas *ntw)
int GBT_is_partial(GBDATA *gb_species, int default_value, bool define_if_undef)
Definition: adali.cxx:634
GB_HASH * GBT_create_species_hash(GBDATA *gb_main)
Definition: adhashtools.cxx:36
void TREE_GC_changed_cb(GcChange whatChanged, AWT_canvas *ntw)
bool is_logically_zoomed()
#define AWAR_FOOTER_MAX_LEN
GB_ERROR GB_push_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2482
void reset_branchlengths()
Definition: TreeNode.cxx:651
#define DOWNCAST(totype, expr)
Definition: downcast.h:141
AW_device_size * get_size_device(AW_area area)
Definition: AW_window.cxx:549
#define AWAR_DTREE_AUTO_UNFOLD
Definition: TreeDisplay.hxx:43
struct Unfixed_cb_parameter * UNFIXED
Definition: cb_base.h:15
void auto_unfold(AP_tree *want_visible)
static void collapse_all_cb(UNFIXED, TREE_canvas *ntw)
const char * read_char_pntr() const
Definition: AW_awar.cxx:171
GcChange
Definition: aw_base.hxx:94
void branchlen2bootstrap()
Definition: TreeNode.cxx:702
#define MODE_TEXT_STANDARD_ZOOMMODE()
Definition: mode_text.h:35
#define AWAR_FOOTER
static void expand_all_cb(UNFIXED, TREE_canvas *ntw)
void NT_insert_collapse_submenu(AW_window_menu_modes *awm, TREE_canvas *ntw)
GBDATA * get_gb_tree() const
Definition: ARB_Tree.hxx:82
void GBT_mark_all_that(GBDATA *gb_main, int flag, bool(*condition)(GBDATA *, void *), void *cd)
Definition: aditem.cxx:323
const TreeNode * ancestor_common_with(const TreeNode *other) const
Definition: TreeNode.cxx:765
const double & ypos() const
#define KEYINFO_RESET
Definition: mode_text.h:24
GBDATA * gb_species_data
Definition: adname.cxx:34
void mark_species_in_tree_that(AP_tree *at, int mark, bool(*condition)(GBDATA *, void *), void *cd)
AWT_RemoveType
Definition: AP_Tree.hxx:35
#define MODE_TEXT_1BUTTON(modeName, leftInfo)
Definition: mode_text.h:27
bool are_distinct(const Position &p1, const Position &p2)
AP_tree * common_ancestor(AP_tree *t1, AP_tree *t2)
void NT_jump_cb(UNFIXED, TREE_canvas *ntw, AP_tree_jump_type jumpType)
static void error(const char *msg)
Definition: mkptypes.cxx:96
static char * create_mark_menu_entry(const char *attrib, const char *entry_template)
const char * get_name() const
Definition: Group.hxx:56
void NT_expand_marked_cb(UNFIXED, TREE_canvas *ntw)
#define KEYINFO_ABORT
Definition: mode_text.h:23
#define MARK_MODE_UPPER_BITS
#define AWAR_SPECIES_NAME
CollapseMode
void multifurcate_whole_tree(const multifurc_limits &below)
Definition: TreeNode.cxx:623
AP_tree_display_style get_tree_style() const
bool is_tree(GBDATA *gb_tree)
Definition: adtree.cxx:955
bool is_inside_folded_group() const
Definition: AP_Tree.cxx:1640
char * read_string() const
Definition: AW_awar.cxx:201
#define AW_COLOR_GROUP_NAME_LEN
void fast_sync_changed_folding(AP_tree *parent_of_all_changes)
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
GB_ERROR GB_pop_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2512
void insert_sub_menu(const char *name, const char *mnemonic, AW_active mask=AWM_ALL)
Definition: AW_window.cxx:642
const char * no_mode_text_defined()
Definition: mode_text.h:38
void NT_set_tree_style(UNFIXED, TREE_canvas *ntw, AP_tree_display_style style)
GBDATA * GBT_find_sequence(GBDATA *gb_species, const char *aliname)
Definition: adali.cxx:670
static AW_window_menu_modes_opengl * awm
void NT_insert_mark_submenus(AW_window_menu_modes *awm, TREE_canvas *ntw, int insert_as_submenu)
bool group_tree(AP_tree *at, CollapseMode mode, int color_group)
long GB_number_of_marked_subentries(GBDATA *gbd)
Definition: adquery.cxx:635
static void insert_color_collapse_submenu(AW_window_menu_modes *awm, TREE_canvas *ntree_canvas)
static bool sequence_is_partial(GBDATA *gb_species, void *cd_partial)
AWT_graphic * gfx
Definition: awt_canvas.hxx:339
static void count_mark_all_cb(UNFIXED, TREE_canvas *ntw)
const AW::Position & get_group_cursor() const
const Group & get_selected_group() const
void set_mode(AWT_COMMAND_MODE mo)
Definition: awt_canvas.hxx:382
bool is_leaf() const
Definition: TreeNode.h:171
void NT_resort_tree_cb(UNFIXED, TREE_canvas *ntw, TreeOrder order)
void scroll(int delta_x, int delta_y, bool dont_update_scrollbars=false)
Definition: AWT_canvas.cxx:703
void request_save_and_zoom_reset()
Definition: awt_canvas.hxx:368
const char * plural(int val)
#define MARK_MODE_LOWER_BITS
void request_structure_update()
Definition: awt_canvas.hxx:365
AP_tree_display_style
Definition: TreeDisplay.hxx:79
char * name
Definition: TreeNode.h:134
AP_tree * locate_selected_group(AP_tree *in_subtree)
const AW::Position & get_cursor() const
AP_tree * get_root_node()
#define MODE_TEXT_1BUTTON_KEYS(modeName, leftInfo, keyInfo)
Definition: mode_text.h:31
AWT_graphic_exports exports
Definition: awt_canvas.hxx:249
void scale_branchlengths(double factor)
Definition: TreeNode.cxx:660
char * AW_get_color_group_name(AW_root *awr, int color_group)
Definition: AW_preset.cxx:1173
void init_device(AW_device *device)
Definition: AWT_canvas.cxx:106
void reset()
Definition: AW_device.cxx:280
static bool are_not_in_tree(GBDATA *gb_species, void *cb_data)
void close_sub_menu()
Definition: AW_window.cxx:483
TreeOrder
Definition: TreeNode.h:35
const AW_bitset AW_SIZE_UNSCALED
Definition: aw_device.hxx:38
void remove_bootstrap()
Definition: TreeNode.cxx:644
void aw_message(const char *msg)
Definition: AW_status.cxx:932
AW_root * get_root()
Definition: aw_window.hxx:348
const double & xpos() const
#define NULp
Definition: cxxforward.h:97
void set_filter(AW_bitset filteri)
Definition: AW_device.cxx:321
GB_ERROR write_string(const char *aw_string)
char * GBT_get_default_alignment(GBDATA *gb_main)
Definition: adali.cxx:675
void sep______________()
Definition: AW_window.cxx:750
bool is_tree_style(AP_tree_display_style style)
void NT_scale_tree(UNFIXED, TREE_canvas *ntw)
const char * local_id(const char *id) const
Definition: AW_window.cxx:744
void GBT_mark_all(GBDATA *gb_main, int flag)
Definition: aditem.cxx:295
static void expand_zombies_cb(UNFIXED, TREE_canvas *ntw)
GB_transaction ta(gb_var)
AW_window * aww
Definition: awt_canvas.hxx:337
GB_CSTR GBT_get_name_or_description(GBDATA *gb_item)
Definition: aditem.cxx:441
char * aw_input(const char *title, const char *prompt, const char *default_input)
Definition: AW_modal.cxx:251
#define MODE_TEXT_2BUTTONS_KEYS(modeName, leftInfo, rightInfo, keyInfo)
Definition: mode_text.h:32
void mark_species_in_tree(AP_tree *at, int mark)
const Position Origin
#define AWAR_DTREE_AUTO_JUMP
Definition: TreeDisplay.hxx:41
AW_awar * get_awar_tree() const
#define KEYINFO_ABORT_AND_RESET
Definition: mode_text.h:25
void NT_reset_branchlengths(UNFIXED, TREE_canvas *ntw)
void NT_reset_lzoom_cb(UNFIXED, TREE_canvas *ntw)
long GBS_read_hash(const GB_HASH *hs, const char *key)
Definition: adhash.cxx:395
static bool species_has_alignment(GBDATA *gb_species, void *cd_use)
static void collapse_terminal_cb(UNFIXED, TREE_canvas *ntw)
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void AWT_GC_changed_cb(GcChange whatChanged, AWT_canvas *scr)
Definition: AWT_canvas.cxx:394
GBDATA * gb_main
Definition: awt_canvas.hxx:336
const char * label
void request_resize()
Definition: awt_canvas.hxx:363
void NT_multifurcate_tree(TREE_canvas *ntw, const TreeNode::multifurc_limits &below)
void NT_reload_tree_event(AW_root *, TREE_canvas *ntw, bool unzoom_and_expose)
virtual void show(AW_device *device)=0
GBDATA * GBT_get_species_data(GBDATA *gb_main)
Definition: aditem.cxx:105