ARB
ad_trees.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : ad_trees.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "tree_position.h"
12 #include "ad_trees.h"
13 #include "NT_tree_cmp.h"
14 
15 #include <CT_ctree.hxx>
16 
17 #include <TreeAdmin.h>
18 #include <TreeRead.h>
19 #include <TreeWrite.h>
20 #include <TreeCallbacks.hxx>
21 
22 #include <sel_boxes.hxx>
23 #include <modules.hxx>
24 #include <TreeAwars.hxx>
25 
26 #include <aw_awars.hxx>
27 #include <aw_edit.hxx>
28 #include <aw_file.hxx>
29 #include <aw_msg.hxx>
30 #include <aw_root.hxx>
31 #include <aw_select.hxx>
32 
33 #include <arb_strbuf.h>
34 #include <arb_file.h>
35 #include <arb_diff.h>
36 #include <arb_defs.h>
37 
38 #include <cctype>
39 #include <config_manager.hxx>
40 #include <xcmd.hxx>
41 
42 #define AWAR_TREE_SAV "ad_tree/"
43 #define AWAR_TREE_TMP "tmp/ad_tree/"
44 
45 #define AWAR_TREE_SECURITY AWAR_TREE_TMP "tree_security"
46 #define AWAR_TREE_REM AWAR_TREE_TMP "tree_rem"
47 #define AWAR_TREE_IMPORT AWAR_TREE_TMP "import_tree"
48 
49 #define AWAR_GROUPXFER_SAV AWAR_TREE_SAV "groupxfer/"
50 
51 #define AWAR_GROUPXFER_SOURCE AWAR_GROUPXFER_SAV "restrict"
52 #define AWAR_GROUPXFER_OVERWRITE_MODE AWAR_GROUPXFER_SAV "overwrite"
53 #define AWAR_GROUPXFER_INGROUP_ABS AWAR_GROUPXFER_SAV "ingroup/abs"
54 #define AWAR_GROUPXFER_INGROUP_REL AWAR_GROUPXFER_SAV "ingroup/rel"
55 #define AWAR_GROUPXFER_INGROUP_LIM AWAR_GROUPXFER_SAV "ingroup/lim"
56 #define AWAR_GROUPXFER_OUTGROUP_ABS AWAR_GROUPXFER_SAV "outgroup/abs"
57 #define AWAR_GROUPXFER_OUTGROUP_REL AWAR_GROUPXFER_SAV "outgroup/rel"
58 #define AWAR_GROUPXFER_OUTGROUP_LIM AWAR_GROUPXFER_SAV "outgroup/lim"
59 #define AWAR_GROUPXFER_UNKNOWN_ABS AWAR_GROUPXFER_SAV "unknown"
60 #define AWAR_GROUPXFER_KEELING AWAR_GROUPXFER_SAV "keeling"
61 #define AWAR_GROUPXFER_ACI AWAR_GROUPXFER_SAV "aci"
62 
63 #define AWAR_TREE_EXPORT_FILEBASE AWAR_TREE_TMP "export_tree"
64 #define AWAR_TREE_EXPORT_FILTER AWAR_TREE_EXPORT_FILEBASE "/filter"
65 #define AWAR_TREE_EXPORT_NAME AWAR_TREE_EXPORT_FILEBASE "/file_name"
66 
67 #define AWAR_TREE_EXPORT_SAV AWAR_TREE_SAV "export_tree/"
68 
69 #define AWAR_TREE_EXPORT_FORMAT AWAR_TREE_EXPORT_SAV "format"
70 #define AWAR_TREE_EXPORT_NDS AWAR_TREE_EXPORT_SAV "NDS"
71 #define AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS AWAR_TREE_EXPORT_SAV "bootstraps"
72 #define AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS AWAR_TREE_EXPORT_SAV "branchlens"
73 #define AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES AWAR_TREE_EXPORT_SAV "groupnames"
74 #define AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS AWAR_TREE_EXPORT_SAV "hide_folded"
75 #define AWAR_TREE_EXPORT_QUOTEMODE AWAR_TREE_EXPORT_SAV "quote_mode"
76 #define AWAR_TREE_EXPORT_NON_ASCII AWAR_TREE_EXPORT_SAV "non_ASCII"
77 #define AWAR_TREE_EXPORT_REPLACE AWAR_TREE_EXPORT_SAV "replace"
78 
79 
80 #define AWAR_TREE_CONSENSE_TMP AWAR_TREE_TMP "consense/"
81 #define AWAR_TREE_CONSENSE_SAV AWAR_TREE_SAV "consense/"
82 
83 #define AWAR_TREE_CONSENSE_TREE AWAR_TREE_CONSENSE_SAV "tree"
84 #define AWAR_TREE_CONSENSE_SELECTED AWAR_TREE_CONSENSE_TMP "selected"
85 
86 static void tree_vars_callback(AW_root *aw_root) {
87  // map tree awars to display database entries (security+comment)
88 
89  if (GLOBAL.gb_main) {
91 
92  char *treename = aw_root->awar(AWAR_TREE_NAME)->read_string();
93  GBDATA *gb_tree = GBT_find_tree(GLOBAL.gb_main, treename);
94 
95  if (!gb_tree) {
96  aw_root->awar(AWAR_TREE_SECURITY)->unmap();
97  aw_root->awar(AWAR_TREE_REM)->unmap();
98  }
99  else {
100  GBDATA *tree_prot = GB_search(gb_tree, "security", GB_FIND);
101  if (!tree_prot) GBT_readOrCreate_int(gb_tree, "security", GB_read_security_write(gb_tree));
102  tree_prot = GB_search(gb_tree, "security", GB_INT);
103 
104  GBDATA *tree_rem = GB_search(gb_tree, "remark", GB_STRING);
105  aw_root->awar(AWAR_TREE_SECURITY)->map(tree_prot);
106  aw_root->awar(AWAR_TREE_REM) ->map(tree_rem);
107  }
108 
109  // create default filename from tree-name:
110  {
111  char *suffix = aw_root->awar(AWAR_TREE_EXPORT_FILTER)->read_string();
112  char *fname = GBS_string_eval(treename, GBS_global_string("*=*1.%s:tree_*=*1", suffix));
113 
114  aw_root->awar(AWAR_TREE_EXPORT_NAME)->write_string(fname); // create default file name
115 
116  free(fname);
117  free(suffix);
118  }
119 
120  free(treename);
121  }
122 }
123 
124 static void update_default_treename_cb(AW_root *aw_root) {
125  // update import tree name depending on file name
127 
128  char *treename = aw_root->awar(AWAR_TREE_IMPORT "/file_name")->read_string();
129  char *treename_nopath = strrchr(treename, '/');
130 
131  if (treename_nopath) {
132  ++treename_nopath;
133  }
134  else {
135  treename_nopath = treename;
136  }
137 
138  char *fname = GBS_string_eval(treename_nopath, "*.tree=tree_*1:*.ntree=tree_*1:*.xml=tree_*1:.=:-=_: =_");
139  aw_root->awar(AWAR_TREE_IMPORT "/tree_name")->write_string(fname);
140 
141  free(fname);
142  free(treename);
143 }
144 
145 static void ad_tree_set_security(AW_root *aw_root) {
146  if (GLOBAL.gb_main) {
148 
149  char *treename = aw_root->awar(AWAR_TREE_NAME)->read_string();
150  GBDATA *gb_tree = GBT_find_tree(GLOBAL.gb_main, treename);
151 
152  if (gb_tree) {
153  long prot = aw_root->awar(AWAR_TREE_SECURITY)->read_int();
154  long old = GB_read_security_delete(gb_tree);
155 
156  GB_ERROR error = NULp;
157  if (old != prot) {
158  error = GB_write_security_delete(gb_tree, prot);
159  if (!error) error = GB_write_security_write(gb_tree, prot);
160  }
161  aw_message_if(error);
162  }
163  free(treename);
164  }
165 }
166 
171 };
172 
173 enum ExportNodeType { // careful: value saved in awar!
177 };
178 
179 static void update_filter_cb(AW_root *root) {
180  const char *filter_type = NULp;
181 
184  filter_type = "xml";
185  break;
186 
189  switch (ExportNodeType(root->awar(AWAR_TREE_EXPORT_NDS)->read_int())) {
190  case AD_TREE_EXPORT_NODE_SPECIES_NAME: filter_type = "tree"; break;
192  case AD_TREE_EXPORT_NODE_NDS_TRUNCATED: filter_type = "ntree"; break;
193  }
194  break;
195 
196  default: nt_assert(0); break;
197  }
198 
199  nt_assert(filter_type);
200  root->awar(AWAR_TREE_EXPORT_FILTER)->write_string(filter_type);
201 }
202 
203 void create_trees_var(AW_root *aw_root, AW_default aw_def) {
204  AW_awar *awar_tree_name = aw_root->awar_string(AWAR_TREE_NAME, NULp, aw_def)->set_srt(SRT_AUTOCORRECT_TREENAME);
205 
206  aw_root->awar_pointer(AWAR_GROUP, NULp, aw_def);
207 
208  TreeAdmin::create_awars(aw_root, aw_def, true);
209 
210  aw_root->awar_int (AWAR_TREE_SECURITY, 0, aw_def);
211  aw_root->awar_string(AWAR_TREE_REM, NULp, aw_def);
212 
213  AW_create_fileselection_awars(aw_root, AWAR_TREE_EXPORT_FILEBASE, "", ".tree", "treefile");
216 
217  aw_root->awar_int(AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS, 0, aw_def);
218  aw_root->awar_int(AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS, 1, aw_def);
219  aw_root->awar_int(AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS, 0, aw_def);
220  aw_root->awar_int(AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES, 1, aw_def);
221 
222  aw_root->awar_int(AWAR_TREE_EXPORT_QUOTEMODE, LABEL_SINGLE_QUOTES, aw_def); // old default behavior
223  aw_root->awar_int(AWAR_TREE_EXPORT_NON_ASCII, 0, aw_def); // changes default behavior (=reject non-ASCII)
224  aw_root->awar_int(AWAR_TREE_EXPORT_REPLACE, 0, aw_def); // old default behavior
225 
226  AW_create_fileselection_awars(aw_root, AWAR_TREE_IMPORT, "", ".tree", "treefile");
227 
228  aw_root->awar_string(AWAR_TREE_IMPORT "/tree_name", "tree_", aw_def)->set_srt(SRT_AUTOCORRECT_TREENAME);
229 
231  awar_tree_name->add_callback(tree_vars_callback);
232  awar_tree_name->map(AWAR_TREE);
234 
237 
238  aw_root->awar_float(AWAR_GROUPXFER_INGROUP_ABS, 1.0, aw_def);
239  aw_root->awar_float(AWAR_GROUPXFER_OUTGROUP_ABS, 1.0, aw_def);
240  aw_root->awar_float(AWAR_GROUPXFER_INGROUP_REL, 0.0, aw_def);
241  aw_root->awar_float(AWAR_GROUPXFER_OUTGROUP_REL, 0.0, aw_def);
242  aw_root->awar_float(AWAR_GROUPXFER_INGROUP_LIM, 0.0, aw_def);
243  aw_root->awar_float(AWAR_GROUPXFER_OUTGROUP_LIM, 100.0, aw_def);
244  aw_root->awar_float(AWAR_GROUPXFER_UNKNOWN_ABS, 0.0001, aw_def);
245  aw_root->awar_float(AWAR_GROUPXFER_KEELING, 0.01, aw_def);
246 
247  aw_root->awar_string(AWAR_GROUPXFER_ACI, "", aw_def);
248 
249  aw_root->awar_string(AWAR_TREE_CONSENSE_TREE, "tree_consensus", aw_def)->set_srt(SRT_AUTOCORRECT_TREENAME);
250  AW_awar *ctree_awar = aw_root->awar_string(AWAR_TREE_CONSENSE_SELECTED, "", aw_def);
251  AWT_registerTreeAwarSimple(ctree_awar);
252 
253  update_filter_cb(aw_root);
254  tree_vars_callback(aw_root);
255 }
256 
257 static void tree_save_cb(AW_window *aww) {
258  AW_root *aw_root = aww->get_root();
259  char *tree_name = aw_root->awar(AWAR_TREE_NAME)->read_string();
260 
261  GB_ERROR error = NULp;
262 
263  if (!tree_name || !strlen(tree_name)) {
264  error = "Please select a tree first";
265  }
266  else {
267  char *fname = aw_root->awar(AWAR_TREE_EXPORT_NAME)->read_string();
268  char *db_name = aw_root->awar(AWAR_DB_NAME)->read_string();
269 
270  SmartPtr<TreeLabeler> labeler;
271  switch (ExportNodeType(aw_root->awar(AWAR_TREE_EXPORT_NDS)->read_int())) {
272  case AD_TREE_EXPORT_NODE_NDS: labeler = new NDS_Labeler(NDS_OUTPUT_LEAFTEXT_UNLIMITED); break;
273  case AD_TREE_EXPORT_NODE_NDS_TRUNCATED: labeler = new NDS_Labeler(NDS_OUTPUT_LEAFTEXT); break;
274  case AD_TREE_EXPORT_NODE_SPECIES_NAME: labeler = new Node_ID_Labeler; break;
275  }
276 
277  ExportTreeType exportType = static_cast<ExportTreeType>(aw_root->awar(AWAR_TREE_EXPORT_FORMAT)->read_int());
278  switch (exportType) {
280  error = TREE_write_XML(GLOBAL.gb_main, db_name, tree_name, *labeler,
282  fname);
283  break;
284 
288 
289  if (aw_root->awar(AWAR_TREE_EXPORT_REPLACE) ->read_int()) quoteMode = LabelQuoting(quoteMode|LABEL_FORCE_REPLACE);
290  if (aw_root->awar(AWAR_TREE_EXPORT_NON_ASCII)->read_int()) quoteMode = LabelQuoting(quoteMode|LABEL_ACCEPT_NON_ASCII);
291 
292  error = TREE_write_Newick(GLOBAL.gb_main, tree_name, *labeler,
297  quoteMode,
298  fname);
299  break;
300  }
301 
302  free(db_name);
303  free(fname);
304  }
305 
306  aww->hide_or_notify(error);
307  free(tree_name);
308 
310 }
311 
313  { AWAR_TREE_EXPORT_FORMAT, "format" },
314  { AWAR_TREE_EXPORT_NDS, "nodetype" },
316  { AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS, "bootstraps" },
317  { AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES, "groupnames" },
318  { AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS, "hidefolded" },
319  { AWAR_TREE_EXPORT_QUOTEMODE, "quotemode" },
320  { AWAR_TREE_EXPORT_NON_ASCII, "nonASCII" },
321  { AWAR_TREE_EXPORT_REPLACE, "replacechars" },
322 
323  { NULp, NULp }
324 };
325 
327  AW_window_simple *aws = new AW_window_simple;
328  aws->init(root, "SAVETREE", "TREE SAVE");
329  aws->load_xfig("tree_export.fig");
330 
331  aws->at("close");
332  aws->callback(AW_POPDOWN);
333  aws->create_button("CLOSE", "CLOSE", "C");
334 
335  aws->at("help");
336  aws->callback(makeHelpCallback("tr_export.hlp"));
337  aws->create_button("HELP", "HELP", "H");
338 
340 
341  aws->at("format");
342  aws->label("Tree format");
343  aws->create_option_menu(AWAR_TREE_EXPORT_FORMAT);
344  aws->insert_option("Newick tree", "N", AD_TREE_EXPORT_FORMAT_NEWICK);
345  aws->insert_option("Newick (pretty, but big)", "P", AD_TREE_EXPORT_FORMAT_NEWICK_PRETTY);
346  aws->insert_option("XML tree (export only)", "X", AD_TREE_EXPORT_FORMAT_XML);
347  aws->update_option_menu();
348 
349  aws->at("labels");
350  aws->label("Tree labels");
351  aws->create_option_menu(AWAR_TREE_EXPORT_NDS);
352  aws->insert_default_option("Species/group ID ('name')", "S", AD_TREE_EXPORT_NODE_SPECIES_NAME);
353  aws->insert_option ("NDS", "N", AD_TREE_EXPORT_NODE_NDS);
354  aws->insert_option ("NDS (truncated)", "t", AD_TREE_EXPORT_NODE_NDS_TRUNCATED);
355  aws->update_option_menu();
356 
357  aws->at("quote");
358  aws->label("Label quoting (Newick only)");
359  aws->create_option_menu(AWAR_TREE_EXPORT_QUOTEMODE);
360  aws->insert_option("none", "n", LABEL_DISALLOW_QUOTES);
361  aws->insert_option("single", "s", LABEL_SINGLE_QUOTES);
362  aws->insert_option("double", "d", LABEL_DOUBLE_QUOTES);
363  aws->insert_option("single (forced)", "i", LABEL_SINGLE_QUOTES | LABEL_FORCE_QUOTES);
364  aws->insert_option("double (forced)", "o", LABEL_DOUBLE_QUOTES | LABEL_FORCE_QUOTES);
365  aws->update_option_menu();
366 
367  aws->at("ascii"); aws->label("Accept non-ASCII chars"); aws->create_toggle(AWAR_TREE_EXPORT_NON_ASCII);
368  aws->at("repl"); aws->label("Replace problem chars"); aws->create_toggle(AWAR_TREE_EXPORT_REPLACE);
369  aws->at("group"); aws->label("Save group names"); aws->create_toggle(AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES);
370  aws->at("hide"); aws->label("Hide folded groups (XML only)"); aws->create_toggle(AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS);
371  aws->at("len"); aws->label("Save branch lengths"); aws->create_toggle(AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS);
372 
373  aws->at("boot");
374  aws->label("Save edge support values/remarks:");
375  aws->create_option_menu(AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS);
376  aws->insert_option("None", "N", SAVE_NO_BRANCH_REMARKS);
377  aws->insert_option("Only values", "v", SAVE_BOOTSTRAPS);
378  aws->insert_option("Force 100%", "1", SAVE_BOOTSTRAPS_INCL_100);
379  aws->insert_option("Only custom", "c", SAVE_CUSTOM_REMARKS);
380  aws->insert_option("Any", "A", SAVE_ANY_BRANCH_REMARKS);
381  aws->insert_option("Any + 100%", "0", SAVE_ANY_BRANCH_REMARKS_INCL_100);
382  aws->update_option_menu();
383 
384  aws->at("save");
385  aws->button_length(10);
386  aws->callback(tree_save_cb);
387  aws->create_button("SAVE", "SAVE", "o");
388 
389  aws->at("cfg");
390  AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "tree_export", tree_export_config_mapping);
391 
392  update_filter_cb(root);
393 
394  return aws;
395 }
396 
397 static char *readXmlTree(char *fname) {
398  // create a temp file
399  char tempFile[] = "newickXXXXXX";
400  int createTempFile = mkstemp(tempFile);
401 
402  if (createTempFile) {
403  GBS_strstruct buf(strlen(fname));
404 
405  // extract path from fname in order to place a copy of dtd file required to validate xml file
406  {
407  char *tmpFname = ARB_strdup(fname);
408  for (char *tok = strtok(tmpFname, "/"); tok;) {
409  char *tmp = tok;
410  tok = strtok(NULp, "/");
411  if (tok) {
412  buf.put('/');
413  buf.cat(tmp);
414  }
415  }
416  free(tmpFname);
417  }
418 
419  // linking arb_tree.dtd file to the Path from where xml file is loaded
420  char *command = GBS_global_string_copy("ln -s %s/lib/dtd/arb_tree.dtd %s/.", GB_getenvARBHOME(), buf.get_data());
422 
423  // execute xml2newick to convert xml format tree to newick format tree
424  command = GBS_global_string_copy("xml2newick %s %s", fname, tempFile);
426 
427  free(command);
428 
429  // return newick format tree file
430  return ARB_strdup(tempFile);
431  }
432  else {
433  printf("Failed to create Temporary File to Parse xml file!\n");
434  return NULp;
435  }
436 }
437 
438 static void tree_load_cb(AW_window *aww) {
439  GB_ERROR error = NULp;
440  AW_root *aw_root = aww->get_root();
441  char *tree_name = aw_root->awar(AWAR_TREE_IMPORT "/tree_name")->read_string();
442 
443  {
444  // @@@L allow to configure translation settings (create GUI+awars)
445  LabelForwarder relabeler; // @@@L use ACI_LabelTranslator here
446 
447  char *pcTreeFormat = aw_root->awar(AWAR_TREE_IMPORT "/filter")->read_string();
448  char *fname = aw_root->awar(AWAR_TREE_IMPORT "/file_name")->read_string();
449  if (strcmp(pcTreeFormat, "xml") == 0) {
450  char *tempFname = readXmlTree(fname);
451 
452  error = TREE_load_to_db(GLOBAL.gb_main, tempFname, tree_name, relabeler);
453 
454  GB_unlink_or_warn(tempFname, NULp);
455  free(tempFname);
456  }
457  else {
458  error = TREE_load_to_db(GLOBAL.gb_main, fname, tree_name, relabeler);
459  }
460 
461  free(fname);
462  free(pcTreeFormat);
463  }
464 
465  aww->hide_or_notify(error);
466  if (!error) aw_root->awar(AWAR_TREE)->write_string(tree_name); // show new tree
467 
468  free(tree_name);
469 }
470 
472  AW_window_simple *aws = new AW_window_simple;
473  aws->init(root, "LOAD_TREE", "TREE LOAD");
474  aws->load_xfig("sel_box_tree.fig");
475 
476  aws->at("close");
477  aws->callback(AW_POPDOWN);
478  aws->create_button("CLOSE", "CLOSE", "C");
479 
480  aws->at("help");
481  aws->callback(makeHelpCallback("tr_import.hlp"));
482  aws->create_button("HELP", "HELP", "H");
483 
484  aws->at("format");
485  aws->create_option_menu(AWAR_TREE_IMPORT "/filter");
486  aws->insert_default_option("Newick", "t", "tree");
487  aws->insert_option("XML", "x", "xml");
488  aws->update_option_menu();
489 
490  aws->at("user");
491  aws->label("Tree name");
492  aws->create_input_field(AWAR_TREE_IMPORT "/tree_name", 15);
493 
495 
496  aws->at("save2");
497  aws->callback(tree_load_cb);
498  aws->create_button("LOAD", "LOAD", "o");
499 
500  aws->window_fit();
501 
502  return aws;
503 }
504 
505 static void ad_move_tree_info(AW_window *aww, bool transferGroups) {
506  AW_root *awr = aww->get_root();
507 
508  char *log_file = NULp;
509  GB_ERROR error = NULp;
510 
513 
514  if (transferGroups) {
515  // log file is only written if transferring groups!
516  char *log_name = GB_unique_filename("arb_node", "log");
517  log_file = GB_create_tempfile(log_name);
518  if (!log_file) error = GB_await_error();
519  free(log_name);
520 
523  }
524 
525  if (!error) {
526  char *src_tree = TreeAdmin::source_tree_awar(awr)->read_string();
527  char *dst_tree = TreeAdmin::dest_tree_awar(awr)->read_string();
528  char *aci = awr->awar(AWAR_GROUPXFER_ACI)->read_string();
529 
530  NT_deselect_group(awr); // avoid crash (if group selected in target tree)
531 
532  GroupMatchScorer userScorer;
533  if (transferGroups) {
534  userScorer.setLimits(RatioLimits(awr->awar(AWAR_GROUPXFER_INGROUP_LIM)->read_float()/100, 1.0),
536 
540 
543  }
544 
545  error = NTREE_move_tree_info(GLOBAL.gb_main, src_tree, dst_tree, log_file, mode, what, userScorer, aci);
546 
547  if (mode == COMPARE_TOPOLOGY && !error) {
548  // if tree is not shown -> provide hint
549  TREE_canvas *canvas_showing_dest = NT_get_canvas_showing_tree(dst_tree, false);
550  if (!canvas_showing_dest) {
551  aw_message(GBS_global_string("Note: annotations added to tree '%s'\n"
552  "Press the right 'Display' button to view that tree", dst_tree));
553  }
554  }
555 
556  if (log_file) {
557  AW_edit(log_file);
558  GB_remove_on_exit(log_file);
559  }
560 
561  free(aci);
562  free(dst_tree);
563  free(src_tree);
564  }
565 
566  aw_message_if(error);
567 
568  free(log_file);
569 }
570 
571 static void swap_source_dest_cb(AW_window *aww) {
572  AW_root *root = aww->get_root();
573 
576 
577  char *old_src = s->read_string();
578  s->write_string(d->read_char_pntr());
579  d->write_string(old_src);
580  free(old_src);
581 }
582 
583 static void copy_tree_awar_cb(UNFIXED, AW_awar *aw_source, AW_awar *aw_dest) {
584  const char *tree = aw_source->read_char_pntr();
585  if (tree && tree[0]) aw_dest->write_string(tree);
586 }
587 
589  AW_root *root = aws->get_root();
590 
591  aws->auto_space(10, 3);
592 
593  aws->at("tree1");
595  aws->at("tree2");
597 
598  AW_awar *awar_displayed_tree = root->awar(AWAR_TREE_NAME);
599 
600  { // let source tree default to currently displayed tree:
601  static bool firstCall = true;
602  if (firstCall) {
603  TreeAdmin::source_tree_awar(root)->write_string(awar_displayed_tree->read_char_pntr());
604  firstCall = false;
605  }
606  }
607 
608 
609  aws->at("select1");
610  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_displayed_tree, TreeAdmin::source_tree_awar(root))); aws->create_autosize_button("SELECT_DISPLAYED1", "Use shown");
611  aws->callback(makeWindowCallback(copy_tree_awar_cb, TreeAdmin::source_tree_awar(root), awar_displayed_tree)); aws->create_autosize_button("DISPLAY_SELECTED1", "Display");
612 
614  aws->create_autosize_button("SWAP", "Swap");
615 
616  aws->at("select2");
617  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_displayed_tree, TreeAdmin::dest_tree_awar(root))); aws->create_autosize_button("SELECT_DISPLAYED2", "Use shown");
618  aws->callback(makeWindowCallback(copy_tree_awar_cb, TreeAdmin::dest_tree_awar(root), awar_displayed_tree)); aws->create_autosize_button("DISPLAY_SELECTED2", "Display");
619 }
620 
621 static AW_window_simple *create_oneTreeSelection(AW_root *root, const char *winId, const char *winTitle, const char *helpFile, AW_awar *awar_displayed_tree) {
622  AW_window_simple *aws = new AW_window_simple;
623  aws->init(root, winId, winTitle);
624  aws->load_xfig("ad_one_tree.fig");
625 
626  aws->at("close");
627  aws->auto_space(10, 3);
628 
629  aws->callback(AW_POPDOWN);
630  aws->create_button("CLOSE", "Close", "C");
631 
632  aws->at("help");
633  aws->callback(makeHelpCallback(helpFile));
634  aws->create_button("HELP", "Help", "H");
635 
636  AW_awar *awar_other_tree = TreeAdmin::dest_tree_awar(root);
637 
638  aws->at("tree");
639  awt_create_TREE_selection_list(GLOBAL.gb_main, aws, awar_other_tree->awar_name);
640 
641  aws->at("select");
642  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_displayed_tree, awar_other_tree)); aws->create_autosize_button("SELECT_DISPLAYED", "Use");
643  aws->callback(makeWindowCallback(copy_tree_awar_cb, awar_other_tree, awar_displayed_tree)); aws->create_autosize_button("DISPLAY_SELECTED", "Display");
644 
645  aws->at("user");
646 
647  return aws;
648 }
649 
651  AW_window_simple *aws = new AW_window_simple;
652  aws->init(root, "CMP_TOPOLOGY", "Compare tree topologies");
653  aws->load_xfig("compare_topo.fig");
654 
655  aws->at("close");
656  aws->callback(AW_POPDOWN);
657  aws->create_button("CLOSE", "Close", "C");
658 
659  aws->at("help");
660  aws->callback(makeHelpCallback("compare_topo.hlp"));
661  aws->create_button("HELP", "Help", "H");
662 
664 
665  aws->at("user");
666  aws->callback(makeWindowCallback(ad_move_tree_info, false));
667  aws->create_autosize_button("CMP_TOPOLOGY", "Compare topologies");
668 
669  return aws;
670 }
671 
673  { AWAR_GROUPXFER_INGROUP_ABS, "ingroup_abs" },
674  { AWAR_GROUPXFER_INGROUP_REL, "ingroup_rel" },
675  { AWAR_GROUPXFER_OUTGROUP_ABS, "outgroup_abs" },
676  { AWAR_GROUPXFER_OUTGROUP_REL, "outgroup_rel" },
677 
678  { AWAR_GROUPXFER_UNKNOWN_ABS, "unknown_abs" },
679  { AWAR_GROUPXFER_KEELING, "keeling" },
680 
681  { AWAR_GROUPXFER_INGROUP_LIM, "ingroup_lim" },
682  { AWAR_GROUPXFER_OUTGROUP_LIM, "outgroup_lim" },
683 
684  { AWAR_GROUPXFER_SOURCE, "sourceGroups" },
685  { AWAR_GROUPXFER_OVERWRITE_MODE, "overwriteGroups" },
686 
687  { AWAR_GROUPXFER_ACI, "aci" },
688 
689  { NULp, NULp },
690 };
691 
693  { "*only_perfect_groups", "Only copy perfectly matching groups with\n * 100% ingroup ratio and\n * 0% outgroup ratio", "ingroup_lim='100';outgroup_lim='0'" },
694 
695  { "*maximize_ingroup_ratio", "Maximize ingroup ratio \n over outgroup ratio.\n(Note: diff of factor 10 is maybe too strong)", "ingroup_abs='0';ingroup_rel='100';outgroup_abs='0';outgroup_rel='10'" },
696  { "*minimize_outgroup_ratio", "Minimize outgroup ratio \n over ingroup ratio.\n(Note: diff of factor 10 is maybe too strong)", "ingroup_abs='0';ingroup_rel='10';outgroup_abs='0';outgroup_rel='100'" },
697 
698  { "*report2name", "custom target group name:\n * add prefix \"XFRD_\" (allows to distinguish newly transferred from existing groups)\n * add suffix reporting penalty", "aci='\"XFRD_\";groupname;\" {penalty = \";penalty;\"}\"'" },
699 
700  { NULp, NULp, NULp },
701 };
702 
703 
704 
706  AW_window_simple *aws = new AW_window_simple;
707  aws->init(root, "COPY_NODE_INFO_OF_TREE", "Move groups");
708  aws->load_xfig("move_groups.fig");
709 
710  aws->button_length(11);
711 
712  aws->at("close");
713  aws->callback(AW_POPDOWN);
714  aws->create_button("CLOSE", "Close", "C");
715 
716  aws->at("help");
717  aws->callback(makeHelpCallback("move_groups.hlp"));
718  aws->create_button("HELP", "Help", "H");
719 
720  const int FLOAT_COLUMNS = 10;
721  const int PERCENT_COLUMNS = 5;
722 
723  aws->at("ipep"); aws->create_input_field(AWAR_GROUPXFER_INGROUP_ABS, FLOAT_COLUMNS);
724  aws->at("irp"); aws->create_input_field(AWAR_GROUPXFER_INGROUP_REL, FLOAT_COLUMNS);
725  aws->at("ilim"); aws->create_input_field(AWAR_GROUPXFER_INGROUP_LIM, PERCENT_COLUMNS);
726 
727  aws->at("opep"); aws->create_input_field(AWAR_GROUPXFER_OUTGROUP_ABS, FLOAT_COLUMNS);
728  aws->at("orp"); aws->create_input_field(AWAR_GROUPXFER_OUTGROUP_REL, FLOAT_COLUMNS);
729  aws->at("olim"); aws->create_input_field(AWAR_GROUPXFER_OUTGROUP_LIM, PERCENT_COLUMNS);
730 
731  aws->at("upep"); aws->create_input_field(AWAR_GROUPXFER_UNKNOWN_ABS, FLOAT_COLUMNS);
732  aws->at("keel"); aws->create_input_field(AWAR_GROUPXFER_KEELING, FLOAT_COLUMNS);
733 
734  aws->at("srcGrps");
735  aws->create_option_menu(AWAR_GROUPXFER_SOURCE);
736  aws->insert_option("all groups", "a", XFER_ALL_GROUPS);
737  aws->insert_option("groups with marked", "m", XFER_GROUPS_WITH_MARKED);
738  aws->update_option_menu();
739 
740  aws->at("tgtGrps");
741  aws->create_option_menu(AWAR_GROUPXFER_OVERWRITE_MODE);
742  aws->insert_option("remove existing groups", "r", REMOVE_EXISTING_GROUPS);
743  aws->insert_option("keep \"newname [was: oldname]\"", "k", KEEP_OLD_NAMES);
744  aws->update_option_menu();
745 
746  aws->at("aci");
747  aws->create_input_field(AWAR_GROUPXFER_ACI);
748 
750 
751  aws->at("go");
752  aws->callback(makeWindowCallback(ad_move_tree_info, true));
753  aws->create_button("GO", "GO", "G");
754 
755  aws->at("cfg");
756  AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "moveGroupInfo", moveGroupInfo_mapping, NULp, moveGroupInfo_predef);
757 
758  return aws;
759 }
760 
761 static void reorder_trees_cb(AW_window *aww, awt_reorder_mode dest) {
762  // moves the tree in the list of trees
763 
764  char *tree_name = aww->get_root()->awar(AWAR_TREE_NAME)->read_string();
765  GB_ERROR error = NULp;
766 
768  GBDATA *gb_treedata = GBT_get_tree_data(GLOBAL.gb_main);
769  GBDATA *gb_moved_tree = GB_entry(gb_treedata, tree_name);
770 
771  if (!gb_moved_tree) {
772  error = "No tree selected";
773  }
774  else {
775  GBT_ORDER_MODE move_mode;
776  GBDATA *gb_target_tree = NULp;
777 
778  switch (dest) {
779  case ARM_UP:
780  move_mode = GBT_INFRONTOF;
781  gb_target_tree = GBT_tree_infrontof(gb_moved_tree);
782  if (gb_target_tree) break;
783  FALLTHROUGH; // move top-tree up = move to bottom
784  case ARM_BOTTOM:
785  move_mode = GBT_BEHIND;
786  gb_target_tree = GBT_find_bottom_tree(GLOBAL.gb_main);
787  break;
788 
789  case ARM_DOWN:
790  move_mode = GBT_BEHIND;
791  gb_target_tree = GBT_tree_behind(gb_moved_tree);
792  if (gb_target_tree) break;
793  FALLTHROUGH; // move bottom-tree down = move to top
794  case ARM_TOP:
795  move_mode = GBT_INFRONTOF;
796  gb_target_tree = GBT_find_top_tree(GLOBAL.gb_main);
797  break;
798  }
799 
800  if (gb_target_tree && gb_target_tree != gb_moved_tree) {
801  error = GBT_move_tree(gb_moved_tree, move_mode, gb_target_tree);
802  }
803  }
804 
805  if (error) aw_message(error);
806  free(tree_name);
807 }
808 
810  static AW_window_simple *aws = NULp;
811 
812  if (!aws) {
813  AW_root *aw_root = awp->get_root();
814 
815  aws = new AW_window_simple;
816  aws->init(aw_root, "TREE_ADMIN", "TREE ADMIN");
817  aws->load_xfig("ad_tree.fig");
818 
819  aws->callback(AW_POPDOWN);
820  aws->at("close");
821  aws->create_button("CLOSE", "CLOSE", "C");
822 
823  aws->callback(makeHelpCallback("treeadm.hlp"));
824  aws->at("help");
825  aws->create_button("HELP", "HELP", "H");
826 
827  aws->button_length(40);
828 
829  aws->at("sel");
830  aws->create_button(NULp, AWAR_TREE_NAME, NULp, "+");
831 
832  aws->at("security");
833  aws->create_option_menu(AWAR_TREE_SECURITY);
834  aws->insert_option("0", "0", 0);
835  aws->insert_option("1", "1", 1);
836  aws->insert_option("2", "2", 2);
837  aws->insert_option("3", "3", 3);
838  aws->insert_option("4", "4", 4);
839  aws->insert_option("5", "5", 5);
840  aws->insert_default_option("6", "6", 6);
841  aws->update_option_menu();
842 
843  aws->at("rem");
844  aws->create_text_field(AWAR_TREE_REM);
845 
846 
847  aws->button_length(20);
848 
850 
851  aws->at("delete");
852  aws->help_text("treeadm.hlp");
853  aws->callback(makeWindowCallback(TreeAdmin::delete_tree_cb, &spec));
854  aws->create_button("DELETE", "Delete", "D");
855 
856  aws->at("rename");
857  aws->help_text("treeadm.hlp");
858  aws->callback(makeCreateWindowCallback(TreeAdmin::create_rename_window, &spec, ""));
859  aws->create_button("RENAME", "Rename", "R");
860 
861  aws->at("copy");
862  aws->help_text("treeadm.hlp");
863  aws->callback(makeCreateWindowCallback(TreeAdmin::create_copy_window, &spec));
864  aws->create_button("COPY", "Copy", "C");
865 
866  aws->at("export");
867  aws->help_text("tr_export.hlp");
868  aws->callback(create_tree_export_window);
869  aws->create_button("EXPORT", "Export", "E");
870 
871  aws->at("import");
872  aws->help_text("tr_import.hlp");
873  aws->callback(create_tree_import_window);
874  aws->create_button("IMPORT", "Import", "I");
875 
876  aws->button_length(0);
877 
878  aws->at("list");
880 
881  aws->at("sort");
883  }
884 
885  aws->activate();
886 }
887 
888 // -----------------------
889 // consense tree
890 
891 
892 static void create_consense_tree_cb(AW_window *aww, AW_selection *selected_trees) {
893  AW_root *aw_root = aww->get_root();
894  GB_ERROR error = NULp;
895 
896  const char *cons_tree_name = aw_root->awar(AWAR_TREE_CONSENSE_TREE)->read_char_pntr();
897  if (!cons_tree_name || !cons_tree_name[0]) {
898  error = "No name specified for the consensus tree";
899  }
900  else {
901  StrArray tree_names;
902  selected_trees->get_values(tree_names);
903 
904  if (tree_names.size()<2) {
905  error = "Not enough trees selected (at least 2 needed)";
906  }
907  else {
909  GB_transaction ta(gb_main);
910 
911  {
912  arb_progress progress("Building consensus tree");
913  ConsensusTreeBuilder tree_builder;
914 
915  progress.subtitle("loading input trees");
916  for (size_t t = 0; t<tree_names.size() && !error; ++t) {
917  TreeRoot *root = new SizeAwareRoot; // will be deleted when tree gets deleted
918  SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, GBT_read_tree(gb_main, tree_names[t], root));
919  if (!tree) {
920  error = GB_await_error();
921  }
922  else {
923  tree_builder.add(tree, tree_names[t], 1.0);
924  }
925  }
926 
927  if (!error) {
928  size_t species_count;
929  TreeNode *cons_tree = tree_builder.get(species_count, error); // triggers 2 implicit progress increments
930 
931  if (!error && progress.aborted()) {
932  error = "user abort";
933  }
934 
935  nt_assert(contradicted(cons_tree, error));
936  if (cons_tree) {
937  char *comment = tree_builder.get_tree_remark();
938  error = GBT_write_tree_with_remark(gb_main, cons_tree_name, cons_tree, comment);
939  free(comment);
940  UNCOVERED();
941  destroy(cons_tree);
942  }
943  }
944  if (error) progress.done();
945  }
946  error = ta.close(error);
947  }
948  }
949 
950  if (!error) {
951  aw_root->awar(AWAR_TREE_NAME)->write_string(cons_tree_name); // show in main window
952  }
953 
954  aw_message_if(error);
955 }
956 
958  AW_root *aw_root = aww->get_root();
960 }
961 
963  static AW_window_simple *aws = NULp;
964  if (!aws) {
965  aws = new AW_window_simple;
966  aws->init(aw_root, "CONSENSE_TREE", "Consensus Tree");
967  aws->load_xfig("ad_cons_tree.fig");
968 
969  aws->auto_space(10, 10);
970 
971  aws->callback(AW_POPDOWN);
972  aws->at("close");
973  aws->create_button("CLOSE", "CLOSE", "C");
974 
975  aws->callback(makeHelpCallback("consense_tree.hlp"));
976  aws->at("help");
977  aws->create_button("HELP", "HELP", "H");
978 
979  aws->at("list");
981  AW_selection *selected_trees = awt_create_subset_selection_list(aws, all_trees->get_sellist(), "selected", "add", "sort");
982 
983  aws->at("name");
984  aws->create_input_field(AWAR_TREE_CONSENSE_TREE);
985 
986  aws->button_length(0);
987  aws->callback(use_selected_as_target_cb);
988  aws->create_button("USE_AS_TARGET", "#moveLeft.xpm");
989 
990  aws->at("build");
991  aws->callback(makeWindowCallback(create_consense_tree_cb, selected_trees));
992  aws->create_autosize_button("BUILD", "Build consensus tree", "B");
993  }
994  return aws;
995 }
996 
998  // combines relative positions of a subtree in 2 trees (source- and target-tree).
999  // provides compare operations for SortByTopo
1000 
1001  TreeRelativePosition source; // in source tree ("ordering tree")
1002  TreeRelativePosition target; // in target tree ("modified tree")
1003 
1004 public:
1005 
1007  : source(s),
1008  target(t)
1009  {
1010  nt_assert(target.is_known());
1011  }
1013  : source(c1.source, c2.source),
1014  target(c1.target, c2.target)
1015  {}
1016 
1017  int compare(const CombinedPosInfo &right) const {
1018  // result similar to strcmp(this, right)
1019  if (!source.is_known() || !right.source.is_known()) {
1020  // one subtree is completely unknown in source-tree
1021  // => keep target-tree order
1022  return target.compare(right.target);
1023  }
1024  return source.compare(right.source);
1025  }
1026 };
1027 
1028 class SortByTopo : virtual Noncopyable {
1029  TreePositionLookup source_pos; // in ordering topology
1030  const TreePositionLookup *target_pos; // in target topology (used where source_pos does not provide order)
1031 
1032  CombinedPosInfo reorder_subtree_rec(TreeNode *node) { // similar to ../ARBDB/TreeNode.cxx@reorder_subtree
1033  static const char *smallest_leafname; // has to be set to the alphabetically smallest name (when function exits)
1034 
1035  if (node->is_leaf()) {
1036  smallest_leafname = node->name;
1037  return CombinedPosInfo(source_pos.relative(node->name),
1038  target_pos->relative(node->name));
1039  }
1040 
1041  CombinedPosInfo leftInfo = reorder_subtree_rec(node->get_leftson());
1042  const char *smallest_left = smallest_leafname;
1043  CombinedPosInfo rightInfo = reorder_subtree_rec(node->get_rightson());
1044  const char *smallest_right = smallest_leafname;
1045 
1046  bool left_leafname_bigger = strcmp(smallest_left, smallest_right)>0;
1047  smallest_leafname = left_leafname_bigger ? smallest_right : smallest_left;
1048 
1049  {
1050  int cmp = leftInfo.compare(rightInfo);
1051  if (cmp>0 || (cmp == 0 && left_leafname_bigger)) {
1052  node->swap_sons();
1053  }
1054  }
1055 
1056  return CombinedPosInfo(leftInfo, rightInfo);
1057  }
1058 public:
1059 
1061  : source_pos(by),
1062  target_pos(NULp)
1063  {}
1064 
1065 #if defined(UNIT_TESTS)
1066  TreeRelativePosition sourcePos(const char *name) { return source_pos.relative(name); }
1067 #endif
1068 
1070  TreePositionLookup tpos(tree);
1071  LocallyModify<const TreePositionLookup*> provide(target_pos, &tpos);
1072  reorder_subtree_rec(tree);
1073  }
1074 };
1075 
1076 static GB_ERROR sort_tree_by_other_tree(GBDATA *gb_main, TreeNode *tree, const char *other_tree) {
1077  GB_ERROR error = NULp;
1078  GB_transaction ta(gb_main);
1079 
1080  TreeNode *otherTree = GBT_read_tree(gb_main, other_tree, new SimpleRoot);
1081  if (!otherTree) error = GB_await_error();
1082  else {
1083  SortByTopo sorter(otherTree);
1084  destroy(otherTree);
1085  sorter.reorder_subtree(tree);
1086  }
1087  return error;
1088 }
1089 
1091  const char *other_tree = TreeAdmin::dest_tree_awar(AW_root::SINGLETON)->read_char_pntr();
1092  error = sort_tree_by_other_tree(GLOBAL.gb_main, tree, other_tree);
1093  return !error;
1094 }
1095 
1098  aw_message_if(error);
1099 }
1100 
1102  AW_window_simple *aws = create_oneTreeSelection(aw_root, ntw->aww->local_id("SORT_BY_OTHER"), ntw->suffixed_title("Sort tree by other tree"), "resortbyother.hlp", ntw->get_awar_tree());
1103 
1104  aws->callback(makeWindowCallback(sort_tree_by_other_tree_cb, ntw));
1105  aws->create_autosize_button("RESORT", "Sort according to source tree");
1106 
1107  return aws;
1108 }
1109 
1110 // ---------------------------
1111 // multifurcate tree
1112 
1113 #define AWAR_MFURC "tree/multifurc/"
1114 #define AWAR_MFURC_CONSIDER_BOOTSTRAP AWAR_MFURC "use_bs"
1115 #define AWAR_MFURC_CONSIDER_LENGTH AWAR_MFURC "use_len"
1116 #define AWAR_MFURC_CONSIDER_TERMINALS AWAR_MFURC "terminals"
1117 #define AWAR_MFURC_LENGTH_LIMIT AWAR_MFURC "len"
1118 #define AWAR_MFURC_BOOTSTRAP_LIMIT AWAR_MFURC "bs"
1119 
1121  aw_root->awar_int (AWAR_MFURC_CONSIDER_BOOTSTRAP, 0, props);
1122  aw_root->awar_int (AWAR_MFURC_CONSIDER_LENGTH, 1, props);
1123  aw_root->awar_int (AWAR_MFURC_CONSIDER_TERMINALS, 0, props);
1124  aw_root->awar_float(AWAR_MFURC_LENGTH_LIMIT, 0.1, props);
1125  aw_root->awar_float(AWAR_MFURC_BOOTSTRAP_LIMIT, 50, props);
1126 }
1128  AW_root *aw_root = ntw->aww->get_root();
1129 
1130  float below_bootstrap = 101.0;
1131  float below_length = 1000000.0;
1132  bool applyAtLeafs = aw_root->awar(AWAR_MFURC_CONSIDER_TERMINALS)->read_int();
1133 
1134  if (aw_root->awar(AWAR_MFURC_CONSIDER_BOOTSTRAP)->read_int()) below_bootstrap = aw_root->awar(AWAR_MFURC_BOOTSTRAP_LIMIT)->read_float();
1135  if (aw_root->awar(AWAR_MFURC_CONSIDER_LENGTH) ->read_int()) below_length = aw_root->awar(AWAR_MFURC_LENGTH_LIMIT) ->read_float();
1136 
1137  NT_multifurcate_tree(ntw, TreeNode::multifurc_limits(below_bootstrap, below_length, applyAtLeafs));
1138 }
1140  AW_window_simple *aws = new AW_window_simple;
1141 
1142  aws->init(aw_root, ntw->aww->local_id("multifurcate"), ntw->suffixed_title("Multifurcate tree"));
1143  aws->at(10, 10);
1144  aws->auto_space(10, 10);
1145 
1146  aws->callback(AW_POPDOWN);
1147  aws->create_button("CLOSE", "CLOSE", "C");
1148 
1149  aws->callback(makeHelpCallback("multifurcate.hlp"));
1150  aws->create_button("HELP", "HELP", "H");
1151 
1152  const int LABEL_LENGTH = 46;
1153  aws->label_length(LABEL_LENGTH);
1154 
1155  aws->at_newline();
1156  aws->label("Multifurcate branches with branchlength below");
1157  aws->create_toggle(AWAR_MFURC_CONSIDER_LENGTH);
1158  aws->create_input_field(AWAR_MFURC_LENGTH_LIMIT, 10);
1159 
1160  aws->at_newline();
1161  aws->label(" AND bootstrap below");
1162  aws->create_toggle(AWAR_MFURC_CONSIDER_BOOTSTRAP);
1163  aws->create_input_field(AWAR_MFURC_BOOTSTRAP_LIMIT, 10);
1164 
1165  aws->label_length(0);
1166  aws->at_newline();
1167  aws->label("Also apply to terminal branches");
1168  aws->create_toggle(AWAR_MFURC_CONSIDER_TERMINALS);
1169 
1170  aws->at_newline();
1171  aws->callback(makeWindowCallback(multifurcation_cb, ntw));
1172  aws->create_autosize_button("MULTIFURCATE", "Multifurcate", "M");
1173 
1174  return aws;
1175 }
1176 
1177 // --------------------------------------------------------------------------------
1178 
1179 #ifdef UNIT_TESTS
1180 #ifndef TEST_UNIT_H
1181 #include <test_unit.h>
1182 #endif
1183 
1184 static const char *getTreeComment(GBDATA *gb_main, const char *treeName) {
1185  GB_transaction ta(gb_main);
1186  return GBT_tree_info_string(gb_main, treeName, -1);
1187 }
1188 
1189 #define TEST_EXPECT_TREE_COMMENT_CONTAINS(treeName,expected) TEST_EXPECT_CONTAINS(getTreeComment(gb_main,treeName),expected)
1190 #define TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeName,expected) TEST_EXPECT_DOESNT_CONTAIN(getTreeComment(gb_main,treeName),expected)
1191 #define TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN__BROKEN(treeName,expected) TEST_EXPECT_DOESNT_CONTAIN__BROKEN(getTreeComment(gb_main,treeName),expected)
1192 
1193 static GB_ERROR sort_namedtree_by_other_tree(GBDATA *gb_main, const char *tree, const char *other_tree) {
1194  GB_ERROR error = NULp;
1195  GB_transaction ta(gb_main);
1196  SizeAwareTree *Tree = DOWNCAST(SizeAwareTree*, GBT_read_tree(gb_main, tree, new SizeAwareRoot));
1197  if (!Tree) error = GB_await_error();
1198  else {
1199  Tree->compute_tree();
1200  error = sort_tree_by_other_tree(gb_main, Tree, other_tree);
1201  if (!error) error = GBT_write_tree(gb_main, tree, Tree);
1202  }
1203  destroy(Tree);
1204  return error;
1205 }
1206 
1207 void TEST_sort_tree_by_other_tree() {
1208  GB_shell shell;
1209  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1210  TEST_REJECT_NULL(gb_main);
1211 
1212  const char *topo_test = "(((((((CloTyro3:1.046,CloTyro4:.061):.026,CloTyro2:.017):.017,CloTyrob:.009):.274,CloInnoc:.371):.057,CloBifer:.388):.124,(((CloButy2:.009,CloButyr:0):.564,CloCarni:.12):.01,CloPaste:.179):.131):.081,((((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522):.053,CelBiazo:.059):.207,CytAquat:.711):.081);";
1213  const char *topo_center = "(((CloPaste:.179,((CloButy2:.009,CloButyr:0):.564,CloCarni:.12):.01):.131,((CloInnoc:.371,((CloTyro2:.017,(CloTyro3:1.046,CloTyro4:.061):.026):.017,CloTyrob:.009):.274):.057,CloBifer:.388):.124):.081,((CelBiazo:.059,((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522):.053):.207,CytAquat:.711):.081);";
1214  const char *topo_bottom = "((CytAquat:.711,(CelBiazo:.059,(CorGluta:.522,(CorAquat:.084,CurCitre:.058):.103):.053):.207):.081,((CloPaste:.179,(CloCarni:.12,(CloButy2:.009,CloButyr:0):.564):.01):.131,(CloBifer:.388,(CloInnoc:.371,(CloTyrob:.009,(CloTyro2:.017,(CloTyro3:1.046,CloTyro4:.061):.026):.017):.274):.057):.124):.081);";
1215 
1216  const char *topo_vs_nj_bs = "(((((((CloTyro3:1.046,CloTyro4:.061):.026,CloTyro2:.017):.017,CloTyrob:.009):.274,CloInnoc:.371):.057,CloBifer:.388):.124,(((CloButyr:0,CloButy2:.009):.564,CloCarni:.12):.01,CloPaste:.179):.131):.081,(((CorGluta:.522,(CorAquat:.084,CurCitre:.058):.103):.053,CelBiazo:.059):.207,CytAquat:.711):.081);";
1217 
1218  TEST_EXPECT_DIFFERENT(topo_test, topo_center);
1219  TEST_EXPECT_DIFFERENT(topo_test, topo_bottom);
1220  TEST_EXPECT_DIFFERENT(topo_center, topo_bottom);
1221 
1222  // create sorted copies of tree_test
1223  {
1224  GB_transaction ta(gb_main);
1225  SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot));
1226  TEST_REJECT_NULL(tree);
1227  TEST_EXPECT_NEWICK(nLENGTH, tree, topo_test);
1228 
1229  tree->reorder_tree(BIG_BRANCHES_TO_CENTER); TEST_EXPECT_NO_ERROR(GBT_write_tree(gb_main, "tree_sorted_center", tree)); TEST_EXPECT_NEWICK(nLENGTH, tree, topo_center);
1230  tree->reorder_tree(BIG_BRANCHES_TO_BOTTOM); TEST_EXPECT_NO_ERROR(GBT_write_tree(gb_main, "tree_sorted_bottom", tree)); TEST_EXPECT_NEWICK(nLENGTH, tree, topo_bottom);
1231 
1232  // test SortByTopo
1233  {
1234  SortByTopo sbt(tree);
1235  const double EPSILON = 0.0001;
1236 
1237  TEST_EXPECT_SIMILAR(sbt.sourcePos("CytAquat").value(), 0.0, EPSILON); // leftmost species (in topo_bottom)
1238  TEST_EXPECT_SIMILAR(sbt.sourcePos("CloTyro4").value(), 1.0, EPSILON); // rightmost species
1239 
1240  TEST_EXPECT_SIMILAR(sbt.sourcePos("CurCitre").value(), 0.2857, EPSILON); // (5 of 15)
1241  TEST_EXPECT_SIMILAR(sbt.sourcePos("CloButy2").value(), 0.5, EPSILON); // center species (8 of 15)
1242  TEST_EXPECT_SIMILAR(sbt.sourcePos("CloTyrob").value(), 0.7857, EPSILON); // (12 of 15)
1243 
1244  TEST_REJECT(sbt.sourcePos("Un-Known").is_known()); // unknown species
1245  }
1246 
1247  tree->reorder_tree(BIG_BRANCHES_TO_EDGE); TEST_EXPECT_NO_ERROR(GBT_write_tree(gb_main, "tree_work", tree));
1248 
1249  destroy(tree);
1250  }
1251 
1252 
1253  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_sorted_center")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_center);
1254  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_sorted_bottom")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_bottom);
1255  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_test")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_test);
1256  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, "tree_work", "tree_nj_bs")); TEST_EXPECT_SAVED_NEWICK(nLENGTH, gb_main, "tree_work", topo_vs_nj_bs);
1257 
1258  // TEST_EXPECT_NO_ERROR(GB_save_as(gb_main, "TEST_trees_save.arb", "b")); // test-save db to examine stored trees (do not commit!)
1259 
1260  GB_close(gb_main);
1261 }
1262 
1263 void TEST_load_trees() {
1264  // test high-level function TREE_load_to_db (see #701).
1265  // test different LabelTranslator|s
1266 
1267  GB_shell shell;
1268  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1269  TEST_REJECT_NULL(gb_main);
1270 
1271  const char *TREE_NAME;
1272 
1273  TREE_NAME = "tree_loaded"; // ../UNIT_TESTER/run/trees/test.tree
1274  TEST_EXPECT_NO_ERROR(TREE_load_to_db(gb_main, "trees/test.tree", TREE_NAME, LabelForwarder()));
1275  TEST_EXPECT_ERROR_CLEAR();
1276  TEST_EXPECT_SAVED_NEWICK(nALL, gb_main, TREE_NAME, "(((s1:.2,s2:.4):.6,(s3:.3,s 4:.1):.1):0,(s5:.02,s-6:.04):.06);");
1277  TEST_EXPECT_TREE_COMMENT_CONTAINS(TREE_NAME, "covering most of tree reader code"); // test comment
1278 
1279  TREE_NAME = "tree_acc_loaded"; // ../UNIT_TESTER/run/trees/acc.tree
1280  TEST_EXPECT_NO_ERROR(TREE_load_to_db(gb_main, "trees/acc.tree", TREE_NAME, ACI_LabelTranslator("readdb(acc)")));
1281  TEST_EXPECT_ERROR_CLEAR();
1282  TEST_EXPECT_SAVED_NEWICK(nALL, gb_main, TREE_NAME,
1283  "(((((((CloTyro3:1.046,CloTyro4:.061):.026,CloTyro2:.017):.017,CloTyrob:.009)'test':.274,CloInnoc:.371):.057,CloBifer:.388):.124,"
1284  "(((CloButy2:.009,CloButyr:0):.564,CloCarni:.12):.01,CloPaste:.179):.131):.081,"
1285  "((((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522):.054,CelBiazo:.059):.207,CytAquat:.711):.081);");
1286 
1287  TREE_NAME = "tree_fullname_loaded"; // ../UNIT_TESTER/run/trees/full_name.tree
1288  TEST_EXPECT_ERROR_CONTAINS(TREE_load_to_db(gb_main, "trees/full_name.tree", TREE_NAME, ACI_LabelTranslator("readdb(name)")),
1289  "Encountered duplicated label 'CLOSTRIDIUM TYROBUTYRICUM' in tree");
1290  TEST_EXPECT_ERROR_CLEAR();
1291 
1292  TEST_EXPECT_ERROR_CONTAINS(TREE_load_to_db(gb_main, "trees/full_name.tree", TREE_NAME, ACI_LabelTranslator("readdb(full_name)")),
1293  "label 'CLOSTRIDIUM TYROBUTYRICUM' is ambiguous (generated for multiple species: CloTyrob,CloTyro2,CloTyro3,CloTyro4)");
1294  TEST_EXPECT_ERROR_CLEAR();
1295 
1296  // @@@C add test loading ../UNIT_TESTER/run/trees/acc_name_fullname.tree
1297 
1298  // tree containing full_name|s, but only non-duplicated ones!
1299  TREE_NAME = "tree_fullname_unique_loaded"; // ../UNIT_TESTER/run/trees/full_name-unique.tree
1300  TEST_EXPECT_NO_ERROR(TREE_load_to_db(gb_main, "trees/full_name-unique.tree", TREE_NAME, ACI_LabelTranslator("readdb(full_name)")));
1301  TEST_EXPECT_ERROR_CLEAR();
1302  TEST_EXPECT_SAVED_NEWICK(nALL, gb_main, TREE_NAME,
1303  "(((CloCarni:.125,CloPaste:.249):.074,(CloBifer:.16,CloInnoc:.58):.149):0,"
1304  "(CytAquat:.33,((CorAquat:.08,CurCitre:.018):.071,(CelBiazo:.001,CorGluta:.326):.127):.061):.073);");
1305 
1306  // same tree as above, but added one ambiguous species.
1307  TREE_NAME = "tree_fullname_unique_loaded"; // ../UNIT_TESTER/run/trees/acc_name_fullname-nondup.tree
1308  TEST_EXPECT_NO_ERROR(TREE_load_to_db(gb_main, "trees/acc_name_fullname-nondup.tree", TREE_NAME, ACI_LabelTranslator("readdb(full_name);\", \";readdb(name);\", \";readdb(acc)")));
1309  TEST_EXPECT_ERROR_CLEAR();
1310  TEST_EXPECT_SAVED_NEWICK(nALL, gb_main, TREE_NAME, // @@@ this test is useless atm (should extract 'full_name' from labels -> then should fail)
1311  "(((CloCarni:.15,CloPaste:.227):.081,(CloBifer:.261,(CloInnoc:.476,CloTyro2:.279):.001):.137):0,"
1312  "(CytAquat:.369,((CorAquat:.048,(CelBiazo:.001,CorGluta:.327):.166):.046,CurCitre:.003):.054):.094);");
1313 
1314  // @@@C read same tree again. extract full name from input AND from species => shall fail with ambig-error!
1315 
1316 #define TRANSLATION_FAILURE_CONTAINS(aci, errorpart) TEST_EXPECT_ERROR_CONTAINS(TREE_load_to_db(gb_main, "trees/acc.tree", "tree_anyname", ACI_LabelTranslator(aci)), errorpart);
1317  // ---------------------------
1318  // test error cases:
1319  TRANSLATION_FAILURE_CONTAINS("kajshdui", "Unknown command 'kajshdui'");
1320  // TRANSLATION_FAILURE_CONTAINS("readdb(acc)|head(2)", "duplicated identifier 'AR' generated (for species 'CelBiazo' and 'CorAquat')"); // @@@ !no longer happens. reactivate together with input-label-aci 'head(2)'!
1321  TRANSLATION_FAILURE_CONTAINS("readdb(noSuchField)", "empty identifier generated (for species 'CelBiazo')");
1322 
1323  // @@@C test failing because of duplicated input labels
1324  // @@@C test failing because of duplicated identifiers generated from input labels
1325 
1326  // TEST_EXPECT_NO_ERROR(GB_save_as(gb_main, "TEST_trees_save.arb", "b")); // test-save db to examine stored trees (do not commit!)
1327 
1328  GB_close(gb_main);
1329 }
1330 
1331 void TEST_move_node_info() {
1332  GB_shell shell;
1333  GBDATA *gb_main = GB_open("TEST_trees.arb", "r");
1334 
1335  const char *treeTarget1 = "tree_removal";
1336  const char *treeTarget2 = "tree_test";
1337  const char *treeSortby1 = "tree_removal_copy";
1338  const char *treeSortby2 = "tree_test_copy";
1339 
1340  const char *treeSource1 = treeSortby2; // contains 1 group ("test")
1341  const char *treeSource2 = "tree_tree2"; // contains 2 groups ("g2" + "outer")
1342  const char *treeSource3 = "tree_groups"; // contains 5 groups
1343 
1344 #define GROUP_TEST "(CloTyrob,(CloTyro2,(CloTyro3,CloTyro4)))"
1345 #define GROUP_TEST_FLIPPED "(((CloTyro3,CloTyro4),CloTyro2),CloTyrob)"
1346 
1347 #define NAMED_GROUP_TEST GROUP_TEST "'test'"
1348 #define OVERWRITTEN_GROUP_TEST GROUP_TEST "'g2 [was test]'"
1349 
1350  const char *org_topo1 = "((CloInnoc," GROUP_TEST "),(CloBifer,((CloCarni,CurCitre),((CloPaste,(Zombie1,(CloButy2,CloButyr))),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2))))))));";
1351  const char *org_topo2 = "((((" GROUP_TEST_FLIPPED ",CloInnoc),CloBifer),(((CloButy2,CloButyr),CloCarni),CloPaste)),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat));";
1352 
1353  // (index convention := source target)
1354  const char *unwanted_topo11 = "((CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)))),((CloPaste,(Zombie1,(CloButy2,CloButyr))),((CloCarni,CurCitre),(CloBifer,(CloInnoc," NAMED_GROUP_TEST ")))));";
1355  const char *unwanted_topo21 = "((CloButy2,CloButyr),(Zombie1,(CloPaste,((((CloInnoc," OVERWRITTEN_GROUP_TEST "),CloBifer),(CloCarni,CurCitre)),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)))))))'outer');";
1356 
1357  const char *sorted_topo11 = "(((((CloInnoc," NAMED_GROUP_TEST "),CloBifer),(CloCarni,CurCitre)),(CloPaste,(Zombie1,(CloButy2,CloButyr)))),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)))));";
1358  const char *sorted_topo21 = "(((((((CloInnoc," OVERWRITTEN_GROUP_TEST "),CloBifer),(CloCarni,CurCitre)),(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2))))),CloPaste),Zombie1)'outer',(CloButy2,CloButyr));";
1359  const char *topo32 = "((CloButy2,CloButyr)'upper',(((((" GROUP_TEST_FLIPPED "'low2',CloInnoc),CloBifer),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'low1'),CloPaste),CloCarni));";
1360  const char *topo32_rc = "((CloButy2,CloButyr)'upper',(((((" GROUP_TEST_FLIPPED "'low2',CloInnoc),CloBifer),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'low1'),CloPaste),CloCarni)'lower');"; // @@@ should be same as topo32 (see #451)
1361  const char *topo32_rel = "((CloButy2,CloButyr)" ",(((((" GROUP_TEST_FLIPPED "'low2 [p=0.250000;ir=100.0%;3->4]',CloInnoc),CloBifer)'low1 [p=0.232222;ir=100.0%;7->6]',((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'upper [p=0.510000;ir=100.0%;5->5]'),CloPaste),CloCarni)'lower [p=0.230769;ir=100.0%;10->13]');"; // group 'upper' and 'low1' moved to different locations by relative scoring
1362  const char *topo32_li = "((CloButy2,CloButyr)" ",(((((" GROUP_TEST_FLIPPED "'low2',CloInnoc),CloBifer),((((CorAquat,CurCitre),CorGluta),CelBiazo),CytAquat)'low1'),CloPaste),CloCarni)'lower');"; // group 'upper' filtered by limits
1363 
1364  const char *compared_topo = "(((((((CloInnoc,(CloTyrob,(CloTyro2,(CloTyro3,CloTyro4)))),CloBifer),(CloCarni,CurCitre)'# 2:')'# 2:',(CytAquat,(CelBiazo,(CorGluta,(CorAquat,Zombie2)'# 1:')'# 1:')'# 1:')'# 1:')'# 1:',CloPaste),Zombie1),(CloButy2,CloButyr));";
1365 
1366  const char *LOG = "move_node_info.log";
1367 
1368 // #define TEST_AUTO_UPDATE // uncomment to auto-update expected log-files
1369 #if defined(TEST_AUTO_UPDATE)
1370 # define TEST_LOGS_EXPECTED(expected) TEST_COPY_FILE(LOG, expected)
1371 #else
1372 # define TEST_LOGS_EXPECTED(expected) TEST_EXPECT_TEXTFILES_EQUAL(expected, LOG)
1373 #endif // TEST_AUTO_UPDATE
1374 
1375  // create copies of 'tree_removal' + 'tree_test'
1376  {
1377  GB_transaction ta(gb_main);
1378 
1379  // remove existing comments from trees (already contains some log-entries tested below)
1380  {
1381  const char *resetComment = "<comment reset>";
1382  TEST_EXPECT_NO_ERROR(GBT_write_tree_remark(gb_main, treeTarget1, resetComment));
1383  TEST_EXPECT_NO_ERROR(GBT_write_tree_remark(gb_main, treeTarget2, resetComment));
1384  }
1385 
1386  TEST_EXPECT_NO_ERROR(GBT_copy_tree(gb_main, treeTarget1, treeSortby1));
1387  TEST_EXPECT_NO_ERROR(GBT_copy_tree(gb_main, treeTarget2, treeSortby2));
1388 
1389  TEST_EXPECT_SAVED_NEWICK(nSIMPLE, gb_main, treeTarget1, org_topo1);
1390  TEST_EXPECT_SAVED_NEWICK(nSIMPLE, gb_main, treeTarget2, org_topo2);
1391  }
1392 
1393  GroupMatchScorer defaultScorer;
1394 
1395  // move node info
1396  {
1397  const char *comment_added = "Copied node info from tree_test_copy";
1398  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget1, comment_added);
1399 
1400  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource1, treeTarget1, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, defaultScorer, NULp));
1401  TEST_LOGS_EXPECTED("group_xfer_11.log.expected");
1402 
1403  TEST_EXPECT_SAVED_NEWICK__BROKEN(nSIMPLE, gb_main, treeTarget1, org_topo1); // @@@ moving node info modifies topology; caused by NT_tree_cmp.cxx@NAIVE_ROOTING
1404  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, unwanted_topo11);
1405  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget1, comment_added);
1406 
1407  // @@@ when we have a function to set the root according to another tree (#449),
1408  // use that function here. sorting tree after that, should again result in 'org_topo1'!
1409 
1410  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, treeTarget1, treeSortby1));
1411  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, sorted_topo11);
1412  }
1413  {
1414  const char *comment_added = "Copied node info from tree_groups";
1415  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget2, comment_added);
1416 
1417  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, defaultScorer, NULp));
1418  TEST_LOGS_EXPECTED("group_xfer_32.log.expected");
1419 
1420  TEST_EXPECT_SAVED_NEWICK__BROKEN(nSIMPLE, gb_main, treeTarget2, org_topo2); // @@@ moving node info modifies topology; caused by NT_tree_cmp.cxx@NAIVE_ROOTING
1421  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget2, comment_added);
1422  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32);
1423 
1424  // perform same group-xfer after 1st xfer changed root => inserts 4 instead of 3 groups (obviously caused by changed root position; see #451)
1425  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, defaultScorer, NULp));
1426  TEST_LOGS_EXPECTED("group_xfer_32_rc.log.expected");
1427  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32_rc);
1428 
1429  {
1430  GroupMatchScorer relativeScorer;
1431  relativeScorer.setPerErrorPenalties(0.0, 0.0, 0.0001); // remove absolute penalties for in-/outgroup
1432  relativeScorer.setRelativePenalties(1.0, 1.0); // set relative penalties for in-/outgroup
1433 
1434  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, relativeScorer,
1435  "groupname;\" [p=\";penalty;\";ir=\";ingroup;\";\";oldsize;\"->\";newsize;\"]\""));
1436  TEST_LOGS_EXPECTED("group_xfer_32_rel.log.expected");
1437  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32_rel);
1438  }
1439 
1440  // again perform same group-xfer using ingroup- and outgroup-limit
1441  {
1442  GroupMatchScorer limitedScorer;
1443  // limitedScorer.setLimits(RatioLimits(1.0, 1.0), RatioLimits(0.0, 0.0)); // filters all groups (upper, low2, low1 + lower)
1444  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 1.0)); // filters no group (by definition)
1445  // limitedScorer.setLimits(RatioLimits(0.5, 1.0), RatioLimits(0.0, 1.0)); // group 'upper' placed at position with higher absolute penalty
1446  // limitedScorer.setLimits(RatioLimits(0.75, 1.0), RatioLimits(0.0, 1.0)); // weird (does keel groups)
1447  // limitedScorer.setLimits(RatioLimits(0.9, 1.0), RatioLimits(0.0, 1.0)); // removes group 'upper'
1448  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 0.5)); // filters no group
1449  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 0.1)); // filters groups 'twoleafs' + 'low2' (group 'lower' superseeded by 'low1')
1450  // limitedScorer.setLimits(RatioLimits(0.0, 1.0), RatioLimits(0.0, 0.3)); // filters group 'twoleafs'
1451  // limitedScorer.setLimits(RatioLimits(0.9, 1.0), RatioLimits(0.0, 0.1)); // filters all groups (weird)
1452  limitedScorer.setLimits(RatioLimits(0.7, 1.0), RatioLimits(0.0, 0.3)); // filters group 'upper' + group 'twoleafs'
1453  limitedScorer.setPerErrorPenalties(2.0, 2.0, 0.0002); // all values are 2*default -> result is same, scores are doubled!
1454 
1455  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource3, treeTarget2, LOG, REMOVE_EXISTING_GROUPS, XFER_ALL_GROUPS, limitedScorer, "")); // test empty ACI does same as passing NULp
1456  TEST_LOGS_EXPECTED("group_xfer_32_li.log.expected");
1457  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget2, topo32_li);
1458  }
1459  }
1460 
1461  // add node info
1462  {
1463  const char *comment_added = "Added node info from tree_tree2";
1464  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget1, comment_added);
1465 
1466  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource2, treeTarget1, LOG, KEEP_OLD_NAMES, XFER_ALL_GROUPS, defaultScorer, NULp));
1467  TEST_LOGS_EXPECTED("group_xfer_21.log.expected");
1468 
1469  TEST_EXPECT_SAVED_NEWICK__BROKEN(nSIMPLE, gb_main, treeTarget1, org_topo1); // @@@ moving node info modifies topology; caused by NT_tree_cmp.cxx@NAIVE_ROOTING
1470  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, unwanted_topo21);
1471  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget1, comment_added);
1472 
1473  // @@@ we have a function to set the root according to another tree (#449).
1474  // (see RootSynchronizer::find_best_root_candidate / rootsync_subsetTrees_vs_selected)
1475  // Use that function here. sorting tree after that, should again result in 'org_topo1'!
1476 
1477  TEST_EXPECT_NO_ERROR(sort_namedtree_by_other_tree(gb_main, treeTarget1, treeSortby1));
1478  TEST_EXPECT_SAVED_NEWICK(nGROUP, gb_main, treeTarget1, sorted_topo21);
1479  }
1480 
1481  // compare node info
1482  {
1483  const char *comment_added = "Compared topology with tree_test";
1484  TEST_EXPECT_TREE_COMMENT_DOESNT_CONTAIN(treeTarget1, comment_added);
1485 
1486  TEST_EXPECT_NO_ERROR(NTREE_move_tree_info(gb_main, treeSource1, treeTarget1, NULp, COMPARE_TOPOLOGY, XFER_ALL_GROUPS, defaultScorer, NULp));
1487  TEST_EXPECT_SAVED_NEWICK(nREMARK, gb_main, treeTarget1, compared_topo);
1488  TEST_EXPECT_TREE_COMMENT_CONTAINS(treeTarget1, comment_added);
1489  }
1490 
1491  // test error cases:
1492  {
1493 #define DOESNT_MATTER_ARGS gb_main,treeSource2,treeTarget1,LOG,REMOVE_EXISTING_GROUPS,XFER_ALL_GROUPS
1494 
1495  GroupMatchScorer invalidScoring;
1496 
1497  invalidScoring.setPerErrorPenalties(1.0, 0.0, 0.0001);
1498  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "one outgroup penalty has to be different from zero");
1499 
1500  invalidScoring.setPerErrorPenalties(0.0, 1.0, 0.0001);
1501  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "one ingroup penalty has to be different from zero");
1502 
1503  invalidScoring.setPerErrorPenalties(-1.0, 1.0, 0.0001);
1504  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "invalid negative in/outgroup penalty");
1505 
1506  invalidScoring.setPerErrorPenalties(1.0, 1.0, 0.0001);
1507  invalidScoring.setRelativePenalties(100.0, -100.0);
1508  TEST_EXPECT_ERROR_CONTAINS(NTREE_move_tree_info(DOESNT_MATTER_ARGS, invalidScoring, NULp), "invalid negative in/outgroup penalty");
1509 
1510 #undef DOESNT_MATTER_ARGS
1511  }
1512 
1513  GB_unlink(LOG);
1514  GB_close(gb_main);
1515 }
1516 
1517 __ATTR__REDUCED_OPTIMIZE void TEST_edges() {
1518  GB_shell shell;
1519  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1520  TEST_REJECT_NULL(gb_main);
1521 
1522  {
1523  GB_transaction ta(gb_main);
1524  TreeNode *tree = GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot);
1525 
1526  TreeNode *left = tree->findLeafNamed("CloTyro3"); TEST_REJECT_NULL(left);
1527  TreeNode *node = left->get_father(); TEST_REJECT_NULL(node);
1528  TreeNode *right = node->findLeafNamed("CloTyro4"); TEST_REJECT_NULL(right);
1529 
1530  TEST_EXPECT(node == right->get_father());
1531  TEST_EXPECT(node->get_leftson() == left);
1532  TEST_EXPECT(node->get_rightson() == right);
1533 
1534  TreeNode *parent = node->get_father(); TEST_REJECT_NULL(parent);
1535  TreeNode *brother = parent->findLeafNamed("CloTyro2"); TEST_REJECT_NULL(brother);
1536 
1537  TEST_EXPECT(node->get_brother() == brother);
1538 
1539  TreeNode *grandpa = parent->get_father(); TEST_REJECT_NULL(grandpa);
1540 
1541  // topology:
1542  //
1543  // grandpa
1544  // /
1545  // /
1546  // /
1547  // parent
1548  // /\ .
1549  // / \ .
1550  // / \ .
1551  // node brother
1552  // /\ .
1553  // / \ .
1554  // / \ .
1555  // left right
1556 
1557  // test next() and otherNext() for inner edge 'node->parent'
1558  {
1559  ARB_edge nodeUp = parentEdge(node);
1560 
1561  TEST_EXPECT(node->is_leftson()); // if child is left son..
1562  TEST_EXPECT(nodeUp.next().dest() == grandpa); // .. next() continues rootwards
1563  TEST_EXPECT(nodeUp.counter_next().dest() == brother);
1564 
1565  ARB_edge brotherUp = parentEdge(brother);
1566 
1567  TEST_EXPECT(brother->is_rightson()); // if child is right son..
1568  TEST_EXPECT(brotherUp.next().dest() == node); // .. next() continues with other son
1569  TEST_EXPECT(brotherUp.counter_next().dest() == grandpa);
1570 
1571  ARB_edge down = nodeUp.inverse();
1572 
1573  TEST_EXPECT(down.next().dest() == right); // next descends into right son
1574  TEST_EXPECT(down.counter_next().dest() == left);
1575 
1576  TEST_EXPECT(nodeUp.previous().source() == left);
1577  TEST_EXPECT(nodeUp.counter_previous().source() == right);
1578 
1579  ARB_edge toLeaf(node, left);
1580  TEST_EXPECT(toLeaf.is_edge_to_leaf());
1581 
1582  // all iterators should turn around at leaf:
1583  TEST_EXPECT(toLeaf.next().dest() == node);
1584  TEST_EXPECT(toLeaf.counter_next().dest() == node);
1585 
1586  ARB_edge fromLeaf(left, node);
1587  TEST_EXPECT(fromLeaf.previous().dest() == left);
1588  TEST_EXPECT(fromLeaf.counter_previous().dest() == left);
1589 
1590  ARB_edge rootEdge(tree->get_leftson(), tree->get_rightson());
1591 
1593  TEST_EXPECT(nodeUp.get_type() == EDGE_TO_ROOT);
1594  TEST_EXPECT(fromLeaf.get_type() == EDGE_TO_ROOT);
1595  TEST_EXPECT(down.get_type() == EDGE_TO_LEAF);
1596  TEST_EXPECT(toLeaf.get_type() == EDGE_TO_LEAF);
1597 
1598  // test iterators are inverse functions
1599  {
1600  ARB_edge e[] = { nodeUp, down, toLeaf, fromLeaf, rootEdge };
1601  const int EDGES = ARRAY_ELEMS(e);
1602  for (int i = 0; i<EDGES; ++i) {
1603  TEST_ANNOTATE(GBS_global_string("i=%i", i));
1604 
1605  TEST_EXPECT(e[i].next().previous() == e[i]);
1606  TEST_EXPECT(e[i].previous().next() == e[i]);
1607 
1608  TEST_EXPECT(e[i].counter_next().counter_previous() == e[i]);
1609  TEST_EXPECT(e[i].counter_previous().counter_next() == e[i]);
1610 
1611  ARB_edge inv(e[i].inverse());
1612 
1613  TEST_EXPECT(e[i].counter_next().inverse().next() == inv);
1614  TEST_EXPECT(e[i].counter_previous().inverse().previous() == inv);
1615  TEST_EXPECT(e[i].next().inverse().counter_next() == inv);
1616  TEST_EXPECT(e[i].previous().inverse().counter_previous() == inv);
1617  }
1618  }
1619 
1620  // test adjacent_distance
1621  const double EPSILON = 0.000001;
1622 
1623  const double NLEN = 0.025806;
1624  const double BLEN = 0.017316;
1625  const double PLEN = 0.017167;
1626  const double LLEN = 1.045690;
1627  const double RLEN = 0.060606;
1628 
1630  TEST_EXPECT_SIMILAR(nodeUp.length(), NLEN, EPSILON);
1631  TEST_EXPECT_SIMILAR(down.length(), NLEN, EPSILON);
1632  TEST_EXPECT_SIMILAR(nodeUp.length_or_adjacent_distance(), NLEN, EPSILON);
1633  TEST_EXPECT_SIMILAR(down.length_or_adjacent_distance(), NLEN, EPSILON);
1634 
1635  TEST_EXPECT_SIMILAR(brother->get_branchlength(), BLEN, EPSILON);
1636  TEST_EXPECT_SIMILAR(parent ->get_branchlength(), PLEN, EPSILON);
1637  TEST_EXPECT_SIMILAR(nodeUp.adjacent_distance(), BLEN+PLEN, EPSILON);
1638 
1639  TEST_EXPECT_SIMILAR(left ->get_branchlength(), LLEN, EPSILON);
1640  TEST_EXPECT_SIMILAR(right->get_branchlength(), RLEN, EPSILON);
1641  TEST_EXPECT_SIMILAR(down.adjacent_distance(), LLEN+RLEN, EPSILON);
1642 
1643  // modify lengths
1644  const double MOD_NLEN = 0.123456;
1645  const double MOD_LLEN = 0.246802;
1646 
1647  toLeaf.set_length(MOD_LLEN);
1648  nodeUp.set_length(MOD_NLEN);
1649 
1650  TEST_EXPECT_SIMILAR(toLeaf.length(), MOD_LLEN, EPSILON);
1651  TEST_EXPECT_SIMILAR(nodeUp.length(), MOD_NLEN, EPSILON);
1652  TEST_EXPECT_SIMILAR(down.length(), MOD_NLEN, EPSILON);
1653  }
1654 
1655  destroy(tree);
1656  }
1657 
1658  GB_close(gb_main);
1659 }
1660 
1661 void TEST_remove_bootstraps() {
1662  GB_shell shell;
1663  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1664  TEST_REJECT_NULL(gb_main);
1665 
1666  {
1667  GB_transaction ta(gb_main);
1668  TreeNode *tree = GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot);
1669  TEST_REJECT_NULL(tree);
1670 
1671  const char *topo_org = "(((((((CloTyro3,CloTyro4)'40%',CloTyro2)'0%',CloTyrob)'97%',CloInnoc)'0%',CloBifer)'53%',(((CloButy2,CloButyr),CloCarni)'33%',CloPaste)'97%'),((((CorAquat,CurCitre),CorGluta)'17%',CelBiazo)'40%',CytAquat));";
1672  const char *topo_rem = "(((((((CloTyro3,CloTyro4)" ",CloTyro2)" ",CloTyrob)" ",CloInnoc)" ",CloBifer)" ",(((CloButy2,CloButyr),CloCarni)" ",CloPaste)" "),((((CorAquat,CurCitre),CorGluta)" ",CelBiazo)" ",CytAquat));";
1673 
1674  TEST_EXPECT_NEWICK(nREMARK, tree, topo_org);
1675 
1676  tree->remove_bootstrap();
1677  TEST_EXPECT_NEWICK(nREMARK, tree, topo_rem);
1678 
1679  destroy(tree);
1680  }
1681 
1682  GB_close(gb_main);
1683 }
1684 
1685 void TEST_multifurcate_tree() {
1686  GB_shell shell;
1687  GBDATA *gb_main = GB_open("TEST_trees.arb", "rw");
1688  TEST_REJECT_NULL(gb_main);
1689 
1690  const char *topo_test = "(((((((CloTyro3:1.046,CloTyro4:.061)'40%':.026,CloTyro2:.017)'0%':.017,CloTyrob:.009)'97%:test':.274,CloInnoc:.371)'0%':.057,CloBifer:.388)'53%':.124,(((CloButy2:.009,CloButyr:0):.564" ",CloCarni:.12)'33%':.01" ",CloPaste:.179)'97%':.131):.081,((((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522)'17%':.053,CelBiazo:.059)'40%':.207" ",CytAquat:.711):.081);";
1691  // changes = " +.307 -.371 +.064 "
1692  const char *topo_single = "(((((((CloTyro3:1.046,CloTyro4:.061)'40%':.026,CloTyro2:.017)'0%':.017,CloTyrob:.009)'97%:test':.581,CloInnoc:0" ")'0%':.121,CloBifer:.388)'53%':.124,(((CloButy2:.009,CloButyr:0):.564" ",CloCarni:.12)'33%':.01" ",CloPaste:.179)'97%':.131):.081,((((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522)'17%':.053,CelBiazo:.059)'40%':.207" ",CytAquat:.711):.081);";
1693  const char *topo_bs_less_101_005 = "(((((((CloTyro3:1.098,CloTyro4:.064)" ":0" ",CloTyro2:0" ")" ":0" ",CloTyrob:0" ")'97%:test':.287,CloInnoc:.371)'0%':.057,CloBifer:.388)'53%':.124,(((CloButy2:0" ",CloButyr:0):.578" ",CloCarni:.121)" ":0" ",CloPaste:.181)'97%':.132):.081,((((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522)'17%':.053,CelBiazo:.059)'40%':.207" ",CytAquat:.711):.081);";
1694  const char *topo_bs_less_101_005_NT = "(((((((CloTyro3:1.078,CloTyro4:.062)" ":0" ",CloTyro2:.018)" ":0" ",CloTyrob:.009)'97%:test':.282,CloInnoc:.371)'0%':.057,CloBifer:.388)'53%':.124,(((CloButy2:.009,CloButyr:0):.57" ",CloCarni:.121)" ":0" ",CloPaste:.181)'97%':.132):.081,((((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522)'17%':.053,CelBiazo:.059)'40%':.207" ",CytAquat:.711):.081);";
1695  const char *topo_bs_less_30_005 = "(((((((CloTyro3:1.046,CloTyro4:.061)'40%':.027,CloTyro2:.018)" ":0" ",CloTyrob:.009)'97%:test':.288,CloInnoc:.371)'0%':.057,CloBifer:.388)'53%':.124,(((CloButy2:.009,CloButyr:0):.564" ",CloCarni:.12)'33%':.01" ",CloPaste:.179)'97%':.131):.081,((((CorAquat:.084,CurCitre:.058):.103,CorGluta:.522)'17%':.053,CelBiazo:.059)'40%':.207" ",CytAquat:.711):.081);";
1696  const char *topo_bs_less_30 = "(((((((CloTyro3:1.046,CloTyro4:.061)'40%':.027,CloTyro2:.018)" ":0" ",CloTyrob:.009)'97%:test':.302,CloInnoc:.39)" ":0" ",CloBifer:.407)'53%':.131,(((CloButy2:.009,CloButyr:0):.564" ",CloCarni:.12)'33%':.01" ",CloPaste:.179)'97%':.131):.081,((((CorAquat:.084,CurCitre:.058):.109,CorGluta:.554)" ":0" ",CelBiazo:.062)'40%':.22" ",CytAquat:.711):.081);";
1697  const char *topo_all = "(((((((CloTyro3:0" ",CloTyro4:0" ")" ":0" ",CloTyro2:0" ")" ":0" ",CloTyrob:0" ")'" "test':0" ",CloInnoc:0" ")" ":0" ",CloBifer:0" ")" ":0" ",(((CloButy2:0" ",CloButyr:0):0" ",CloCarni:0)" ":0" ",CloPaste:0)" ":0)" ":0" ",((((CorAquat:0" ",CurCitre:0" "):0" ",CorGluta:0)" ":0" ",CelBiazo:0)" ":0" ",CytAquat:0" "):0" ");";
1698 
1699  const double STABLE_LENGTH = 5.362750;
1700  const double EPSILON = 0.000001;
1701 
1702  for (int test = 1; test<=6; ++test) {
1703  GB_transaction ta(gb_main);
1704  TreeNode *tree = GBT_read_tree(gb_main, "tree_test", new SizeAwareRoot);
1705 
1706  TEST_REJECT_NULL(tree);
1707  if (test == 1) {
1708  TEST_EXPECT_NEWICK(nALL, tree, topo_test);
1709  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1710  }
1711 
1712  switch (test) {
1713  case 1:
1714  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(101, 0.05, true));
1715  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_101_005);
1716  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1717  break;
1718  case 6:
1719  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(101, 0.05, false));
1720  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_101_005_NT);
1721  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1722  break;
1723  case 2:
1724  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(30, 0.05, true));
1725  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_30_005);
1726  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1727  break;
1728  case 3:
1729  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(30, 1000, true));
1730  TEST_EXPECT_NEWICK(nALL, tree, topo_bs_less_30);
1731  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1732  break;
1733  case 4:
1734  tree->multifurcate_whole_tree(TreeNode::multifurc_limits(101, 1000, true)); // multifurcate all
1735  TEST_EXPECT_NEWICK(nALL, tree, topo_all);
1737  break;
1738  case 5: {
1739  TreeNode *CloInnoc = tree->findLeafNamed("CloInnoc");
1740  TEST_REJECT_NULL(CloInnoc);
1741 
1742  parentEdge(CloInnoc).multifurcate();
1743  TEST_EXPECT_NEWICK(nALL, tree, topo_single);
1744 
1745  TEST_EXPECT_SIMILAR(tree->sum_child_lengths(), STABLE_LENGTH, EPSILON);
1746  break;
1747  }
1748  default:
1749  nt_assert(0);
1750  break;
1751  }
1752 
1753  destroy(tree);
1754  }
1755 
1756  GB_close(gb_main);
1757 }
1758 
1759 void TEST_TreeNode_attributes() {
1760  // -> ../UNIT_TESTER/run/trees/bg_exp_p__0.tree
1761  TreeNode *tree = TREE_load("trees/bg_exp_p__0.tree", new SimpleRoot, NULp, false, NULp);
1762 
1763  TreeNode *MabPelag = tree->findLeafNamed("MabPelag");
1764  TreeNode *MabSalin = tree->findLeafNamed("MabSalin");
1765  TreeNode *PaoMaris = tree->findLeafNamed("PaoMaris");
1766 
1767  TEST_EXPECT(MabPelag->father == MabSalin->father); // are brothers
1768 
1769  TreeNode *Mabs = MabPelag->father;
1770  TreeNode *PaoMabs = PaoMaris->father;
1771 
1772  // ((MabPelag, MabSalin), PaoMaris)
1773  // -------- Mabs ------
1774  // -------------- PaoMabs ---------
1775 
1776  TEST_EXPECT(Mabs->father == PaoMabs);
1777 
1778  // is_son_of
1779  TEST_EXPECT(MabPelag->is_son_of(Mabs));
1780  TEST_EXPECT(MabSalin->is_son_of(Mabs));
1781  TEST_EXPECT(Mabs->is_son_of(PaoMabs));
1782  TEST_EXPECT(PaoMaris->is_son_of(PaoMabs));
1783 
1784  // is_inside
1785  TEST_EXPECT(MabPelag->is_inside(Mabs)); // leaf in father
1786  TEST_EXPECT(Mabs->is_inside(PaoMabs)); // node in father
1787  TEST_EXPECT(MabPelag->is_inside(PaoMabs)); // leaf in grandfather
1788  TEST_EXPECT(MabPelag->is_inside(MabPelag)); // self-containment
1789  TEST_REJECT(Mabs->is_inside(MabPelag)); // not: father in child
1790  TEST_REJECT(MabPelag->is_inside(MabSalin)); // not: node in brother
1791 
1792  // is_ancestor_of
1793  TEST_EXPECT(Mabs->is_ancestor_of(MabPelag));
1794  TEST_EXPECT(Mabs->is_ancestor_of(MabSalin));
1795  TEST_REJECT(Mabs->is_ancestor_of(PaoMaris)); // brother is no ancestor
1796  TEST_REJECT(Mabs->is_ancestor_of(Mabs)); // node never is ancestor of itself
1797  TEST_REJECT(Mabs->is_ancestor_of(PaoMabs)); // child cannot be ancestor
1798 
1799  TEST_EXPECT(PaoMabs->is_ancestor_of(MabPelag)); // root of subtree (PaoMabs) is ancestor of all members..
1800  TEST_EXPECT(PaoMabs->is_ancestor_of(MabSalin));
1801  TEST_EXPECT(PaoMabs->is_ancestor_of(PaoMaris));
1802  TEST_EXPECT(PaoMabs->is_ancestor_of(Mabs));
1803  TEST_REJECT(PaoMabs->is_ancestor_of(PaoMabs)); // .. despite itself
1804 
1805  // in_same_branch_as / in_other_branch_than
1806  TEST_EXPECT(MabPelag->in_same_branch_as(MabPelag));
1807  TEST_EXPECT(MabPelag->in_other_branch_than(MabSalin));
1808  TEST_EXPECT(MabPelag->in_other_branch_than(PaoMaris));
1809  TEST_EXPECT(MabPelag->in_same_branch_as(Mabs));
1810  TEST_EXPECT(MabPelag->in_same_branch_as(PaoMabs));
1811 
1812  TEST_EXPECT(PaoMabs->in_same_branch_as(MabPelag));
1813  TEST_EXPECT(PaoMabs->in_same_branch_as(MabSalin));
1814  TEST_EXPECT(PaoMabs->in_same_branch_as(PaoMaris));
1815  TEST_EXPECT(PaoMabs->in_same_branch_as(Mabs));
1816  TEST_EXPECT(PaoMabs->in_same_branch_as(PaoMabs));
1817 
1818  TEST_EXPECT(Mabs->in_same_branch_as(MabPelag));
1819  TEST_EXPECT(Mabs->in_same_branch_as(MabSalin));
1820  TEST_EXPECT(Mabs->in_other_branch_than(PaoMaris));
1821  TEST_EXPECT(Mabs->in_same_branch_as(Mabs));
1822  TEST_EXPECT(Mabs->in_same_branch_as(PaoMabs));
1823 
1824  // ancestor_common_with
1825  TEST_EXPECT(MabPelag->ancestor_common_with(MabSalin) == Mabs);
1826  TEST_EXPECT(MabSalin->ancestor_common_with(MabPelag) == Mabs);
1827  TEST_EXPECT(PaoMaris->ancestor_common_with(MabPelag) == PaoMabs);
1828  TEST_EXPECT(PaoMabs->ancestor_common_with(Mabs) == PaoMabs);
1829  TEST_EXPECT(MabPelag->ancestor_common_with(PaoMabs) == PaoMabs);
1830 
1831  destroy(tree);
1832 }
1833 
1834 #endif // UNIT_TESTS
1835 
1836 // --------------------------------------------------------------------------------
1837 
GBDATA * GBT_find_bottom_tree(GBDATA *gb_main)
Definition: adtree.cxx:1109
const char * GB_ERROR
Definition: arb_core.h:25
bool is_rightson() const
Definition: TreeNode.h:285
NOT4PERL GB_ERROR GBT_move_tree(GBDATA *gb_moved_tree, GBT_ORDER_MODE mode, GBDATA *gb_target_tree)
Definition: adtree.cxx:1304
GB_ERROR NT_with_displayed_tree_do(TREE_canvas *ntw, bool(*displayed_tree_cb)(TreeNode *tree, GB_ERROR &error))
#define AWAR_TREE_EXPORT_NDS
Definition: ad_trees.cxx:70
#define AWAR_DB_NAME
Definition: aw_awar_defs.hxx:6
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
void GB_remove_on_exit(const char *filename)
Definition: adsocket.cxx:1249
AW_awar * set_srt(const char *srt)
Definition: AW_awar.cxx:567
virtual void swap_sons()
Definition: TreeNode.h:620
#define AWAR_TREE_EXPORT_REPLACE
Definition: ad_trees.cxx:77
GB_ERROR TREE_write_XML(GBDATA *gb_main, const char *db_name, const char *tree_name, const TreeLabeler &labeler, bool skip_folded, const char *path)
Definition: TreeWrite.cxx:330
#define TEST_EXPECT_SIMILAR(expr, want, epsilon)
Definition: test_unit.h:1298
GB_ERROR GBT_write_tree_with_remark(GBDATA *gb_main, const char *tree_name, TreeNode *tree, const char *remark)
Definition: adtree.cxx:599
#define AWAR_TREE_EXPORT_FILTER
Definition: ad_trees.cxx:64
AW_window * NT_create_moveGroupInfo_window(AW_root *root)
Definition: ad_trees.cxx:705
TreeNode * findLeafNamed(const char *wantedName)
Definition: TreeNode.cxx:276
static void tree_vars_callback(AW_root *aw_root)
Definition: ad_trees.cxx:86
bool is_known() const
Definition: tree_position.h:47
void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, const StoreConfigCallback &store_cb, const RestoreConfigCallback &load_or_reset_cb, const char *macro_id, const AWT_predefined_config *predef)
#define AWAR_TREE_EXPORT_NAME
Definition: ad_trees.cxx:65
void load_xfig(const char *file, bool resize=true)
Definition: AW_window.cxx:707
static void multifurcation_cb(UNFIXED, TREE_canvas *ntw)
Definition: ad_trees.cxx:1127
static char * readXmlTree(char *fname)
Definition: ad_trees.cxx:397
void AW_edit(const char *path)
Definition: AW_edit.cxx:16
#define AWAR_GROUPXFER_ACI
Definition: ad_trees.cxx:61
#define AWAR_TREE_REM
Definition: ad_trees.cxx:46
void GB_unlink_or_warn(const char *path, GB_ERROR *error)
Definition: arb_file.cxx:206
void reorder_subtree(TreeNode *tree)
Definition: ad_trees.cxx:1069
GBDATA * GBT_tree_behind(GBDATA *gb_tree)
Definition: adtree.cxx:1095
void at(int x, int y)
Definition: AW_at.cxx:93
#define AWAR_GROUPXFER_OUTGROUP_LIM
Definition: ad_trees.cxx:58
char * get_tree_remark() const
Definition: CT_ctree.cxx:213
void AW_create_standard_fileselection(AW_window *aws, const char *awar_prefix)
Definition: aw_file.hxx:30
void AWT_registerTreeAwarSimple(AW_awar *awar)
Definition: TreeAwars.cxx:222
ARB_edge_type get_type() const
Definition: TreeNode.h:833
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
#define AWAR_GROUPXFER_SOURCE
Definition: ad_trees.cxx:51
static void swap_source_dest_cb(AW_window *aww)
Definition: ad_trees.cxx:571
TreeNode * GBT_read_tree(GBDATA *gb_main, const char *tree_name, TreeRoot *troot)
Definition: adtree.cxx:889
long read_int() const
Definition: AW_awar.cxx:184
AW_window * NT_create_multifurcate_tree_window(AW_root *aw_root, TREE_canvas *ntw)
Definition: ad_trees.cxx:1139
#define AWAR_MFURC_CONSIDER_LENGTH
Definition: ad_trees.cxx:1115
#define AWAR_TREE_CONSENSE_TREE
Definition: ad_trees.cxx:83
ARB_edge inverse() const
Definition: TreeNode.h:861
NOT4PERL long * GBT_readOrCreate_int(GBDATA *gb_container, const char *fieldpath, long default_value)
Definition: adtools.cxx:402
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
#define SRT_AUTOCORRECT_TREENAME
Definition: arbdbt.h:80
#define AWAR_MFURC_CONSIDER_TERMINALS
Definition: ad_trees.cxx:1116
char * GBS_string_eval(const char *insource, const char *icommand)
Definition: admatch.cxx:699
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
static void update_default_treename_cb(AW_root *aw_root)
Definition: ad_trees.cxx:124
#define AWAR_GROUPXFER_INGROUP_LIM
Definition: ad_trees.cxx:55
ARB_edge previous() const
Definition: TreeNode.h:882
GBT_LEN length() const
Definition: TreeNode.h:840
void cat(const char *from)
Definition: arb_strbuf.h:204
#define LOG(x)
GBDATA * GBT_get_tree_data(GBDATA *gb_main)
Definition: adtree.cxx:27
int GB_unlink(const char *path)
Definition: arb_file.cxx:188
void get_values(StrArray &intoArray)
Definition: aw_select.hxx:198
ARB_edge rootEdge(TreeRoot *root)
Definition: TreeNode.h:965
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
#define AWAR_GROUP
Definition: ad_trees.h:19
int compare(const CombinedPosInfo &right) const
Definition: ad_trees.cxx:1017
#define AWAR_GROUPXFER_OUTGROUP_REL
Definition: ad_trees.cxx:57
static AWT_config_mapping_def moveGroupInfo_mapping[]
Definition: ad_trees.cxx:672
GB_CSTR GB_getenvARBHOME(void)
Definition: adsocket.cxx:580
static void ad_tree_set_security(AW_root *aw_root)
Definition: ad_trees.cxx:145
AW_window * NT_create_sort_tree_by_other_tree_window(AW_root *aw_root, TREE_canvas *ntw)
Definition: ad_trees.cxx:1101
GB_ERROR ARB_system(const char *cmd, XCmdType boundExectype)
Definition: xcmd.cxx:69
#define DOWNCAST(totype, expr)
Definition: downcast.h:141
const char * suffixed_title(const char *primary_title) const
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:231
struct Unfixed_cb_parameter * UNFIXED
Definition: cb_base.h:15
ARB_edge next() const
Definition: TreeNode.h:871
ARB_edge parentEdge(TreeNode *son)
Definition: TreeNode.h:950
void setPerErrorPenalties(double ingroup_pep, double outgroup_pep, double unfound_pep)
Definition: NT_tree_cmp.h:154
GB_ERROR GBT_write_tree_remark(GBDATA *gb_main, const char *tree_name, const char *remark)
Definition: adtree.cxx:562
#define TEST_EXPECT_SAVED_NEWICK__BROKEN(format, gb_main, treename, expected_newick)
Definition: test_unit.h:1485
const double EPSILON
Definition: aw_position.hxx:73
const char * read_char_pntr() const
Definition: AW_awar.cxx:168
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
static AW_root * SINGLETON
Definition: aw_root.hxx:102
#define AWAR_TREE_EXPORT_FORMAT
Definition: ad_trees.cxx:69
#define AWAR_TREE_IMPORT
Definition: ad_trees.cxx:47
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
#define TEST_EXPECT(cond)
Definition: test_unit.h:1328
char * GB_create_tempfile(const char *name)
Definition: adsocket.cxx:1213
static void tree_save_cb(AW_window *aww)
Definition: ad_trees.cxx:257
void popup_tree_admin_window(AW_window *awp)
Definition: ad_trees.cxx:809
bool in_other_branch_than(const TreeNode *other) const
Definition: TreeNode.h:300
GBT_ORDER_MODE
Definition: arbdbt.h:44
#define TEST_EXPECT_NEWICK(format, tree, expected_newick)
Definition: test_unit.h:1481
AW_window * NT_create_consense_window(AW_root *aw_root)
Definition: ad_trees.cxx:962
const TreeNode * ancestor_common_with(const TreeNode *other) const
Definition: TreeNode.cxx:901
static void reorder_trees_cb(AW_window *aww, awt_reorder_mode dest)
Definition: ad_trees.cxx:761
int compare(const TreeRelativePosition &right) const
Definition: tree_position.h:52
AW_awar * awar_float(const char *var_name, float default_value=0.0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:612
AW_awar * dest_tree_awar(AW_root *root)
Definition: TreeAdmin.cxx:39
#define AWAR_GROUPXFER_INGROUP_REL
Definition: ad_trees.cxx:54
void create_awars(AW_root *root, AW_default aw_def, bool registerTreeAwar)
Definition: TreeAdmin.cxx:31
AW_window * NT_create_compareTopologies_window(AW_root *root)
Definition: ad_trees.cxx:650
const char * GBT_tree_info_string(GBDATA *gb_main, const char *tree_name, int maxTreeNameLen)
Definition: adtree.cxx:1173
static void copy_tree_awar_cb(UNFIXED, AW_awar *aw_source, AW_awar *aw_dest)
Definition: ad_trees.cxx:583
Generic smart pointer.
Definition: smartptr.h:149
bool is_leftson() const
Definition: TreeNode.h:280
int GB_read_security_write(GBDATA *gbd)
Definition: arbdb.cxx:1572
bool aborted()
Definition: arb_progress.h:335
static void tree_load_cb(AW_window *aww)
Definition: ad_trees.cxx:438
static AWT_config_mapping_def tree_export_config_mapping[]
Definition: ad_trees.cxx:312
GBDATA * GBT_find_top_tree(GBDATA *gb_main)
Definition: adtree.cxx:1101
void delete_tree_cb(AW_window *aww, const Spec *spec)
Definition: TreeAdmin.cxx:47
#define AWAR_TREE_NAME
Definition: ad_trees.h:18
void setRelativePenalties(double ingroup_inv_relpen, double outgroup_relpen)
Definition: NT_tree_cmp.h:159
GB_ERROR GBT_write_tree(GBDATA *gb_main, const char *tree_name, TreeNode *tree)
Definition: adtree.cxx:552
GB_ERROR TREE_write_Newick(GBDATA *gb_main, const char *tree_name, const TreeLabeler &labeler, bool save_branchlengths, BootstrapSaveStyle bootstrap_style, bool save_groupnames, bool pretty, LabelQuoting quoteMode, const char *path)
Definition: TreeWrite.cxx:406
void add(SizeAwareTree *&tree, const char *treename, double weight)
Definition: CT_ctree.hxx:65
void setLimits(const RatioLimits &ingroupLimits, const RatioLimits &outgroupLimits)
Definition: NT_tree_cmp.h:147
#define TEST_REJECT(cond)
Definition: test_unit.h:1330
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1325
void multifurcate()
Definition: TreeNode.cxx:580
#define AWAR_TREE_EXPORT_INCLUDE_GROUPNAMES
Definition: ad_trees.cxx:73
TreeNode * father
Definition: TreeNode.h:223
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define AWAR_TREE_EXPORT_QUOTEMODE
Definition: ad_trees.cxx:75
void AW_create_fileselection_awars(AW_root *awr, const char *awar_base, const char *directories, const char *filter, const char *file_name)
Definition: AW_file.cxx:72
TreeNode * TREE_load(const char *path, TreeRoot *troot, char **commentPtr, bool allow_length_scaling, char **warningPtr)
Definition: TreeRead.cxx:734
awt_reorder_mode
Definition: modules.hxx:22
static bool sort_dtree_by_other_tree_cb(TreeNode *tree, GB_ERROR &error)
Definition: ad_trees.cxx:1090
#define AWAR_TREE
GB_ERROR GBT_copy_tree(GBDATA *gb_main, const char *source_name, const char *dest_name)
Definition: adtree.cxx:1361
void NT_create_twoTreeSelection(AW_window *aws)
Definition: ad_trees.cxx:588
static AWT_predefined_config moveGroupInfo_predef[]
Definition: ad_trees.cxx:692
bool in_same_branch_as(const TreeNode *other) const
Definition: TreeNode.h:296
AW_window * create_rename_window(AW_root *root, const Spec *spec, const char *specialized)
Definition: TreeAdmin.cxx:217
TREE_canvas * NT_get_canvas_showing_tree(const char *tree_name, bool forceDisplay)
TreeNode * get_brother()
Definition: TreeNode.h:489
ARB_edge counter_previous() const
Definition: TreeNode.h:905
static void update_filter_cb(AW_root *root)
Definition: ad_trees.cxx:179
#define AWAR_GROUPXFER_OUTGROUP_ABS
Definition: ad_trees.cxx:56
#define cmp(h1, h2)
Definition: admap.cxx:50
GroupsToTransfer
Definition: NT_tree_cmp.h:27
void multifurcate_whole_tree(const multifurc_limits &below)
Definition: TreeNode.cxx:625
#define AWAR_GROUPXFER_UNKNOWN_ABS
Definition: ad_trees.cxx:59
#define AWAR_MFURC_BOOTSTRAP_LIMIT
Definition: ad_trees.cxx:1118
bool is_son_of(const TreeNode *Father) const
Definition: TreeNode.h:276
char * read_string() const
Definition: AW_awar.cxx:198
GB_ERROR GB_write_security_write(GBDATA *gbd, unsigned long level)
Definition: arbdb.cxx:1584
static void create_consense_tree_cb(AW_window *aww, AW_selection *selected_trees)
Definition: ad_trees.cxx:892
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:606
void awt_create_order_buttons(AW_window *aws, awt_orderfun reorder_cb, AW_CL cl_user)
Definition: modules.cxx:17
SortByTopo(const TreeNode *by)
Definition: ad_trees.cxx:1060
AW_awar * unmap()
Definition: AW_awar.cxx:596
Definition: arbdb.h:86
AW_selection * awt_create_subset_selection_list(AW_window *aww, AW_selection_list *parent_selection, const char *at_box, const char *at_add, const char *at_sort, bool autocorrect_subselection, SubsetChangedCb subChanged_cb, AW_CL cl_user)
Definition: sel_boxes.cxx:1171
AW_DB_selection * awt_create_TREE_selection_list(GBDATA *gb_main, AW_window *aws, const char *varname)
Definition: sel_boxes.cxx:225
void AW_refresh_fileselection(AW_root *awr, const char *awar_prefix)
Definition: AW_file.cxx:944
bool is_ancestor_of(const TreeNode *descendant) const
Definition: TreeNode.h:293
ExportNodeType
Definition: ad_trees.cxx:173
void create_autosize_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, unsigned xtraSpace=1)
Definition: AW_button.cxx:421
float read_float() const
Definition: AW_awar.cxx:177
#define __ATTR__REDUCED_OPTIMIZE
Definition: test_unit.h:83
#define AWAR_TREE_CONSENSE_SELECTED
Definition: ad_trees.cxx:84
#define nt_assert(cond)
Definition: NT_local.h:27
#define AWAR_MFURC_CONSIDER_BOOTSTRAP
Definition: ad_trees.cxx:1114
#define AWAR_GROUPXFER_INGROUP_ABS
Definition: ad_trees.cxx:53
void NT_create_multifurcate_tree_awars(AW_root *aw_root, AW_default props)
Definition: ad_trees.cxx:1120
void create_trees_var(AW_root *aw_root, AW_default aw_def)
Definition: ad_trees.cxx:203
char * GB_unique_filename(const char *name_prefix, const char *suffix)
Definition: adsocket.cxx:1224
char * awar_name
Definition: aw_awar.hxx:103
int GB_read_security_delete(GBDATA *gbd)
Definition: arbdb.cxx:1580
TreeNode * dest() const
Definition: TreeNode.h:835
static void ad_move_tree_info(AW_window *aww, bool transferGroups)
Definition: ad_trees.cxx:505
bool is_leaf() const
Definition: TreeNode.h:263
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:632
void auto_space(int xspace, int yspace)
Definition: AW_at.cxx:259
GroupTransferMode
Definition: NT_tree_cmp.h:21
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:35
#define AWAR_GROUPXFER_KEELING
Definition: ad_trees.cxx:60
static AW_window * create_tree_export_window(AW_root *root)
Definition: ad_trees.cxx:326
bool is_inside(const TreeNode *subtree) const
Definition: TreeNode.h:290
GB_ERROR TREE_load_to_db(GBDATA *gb_main, const char *treefile, const char *tree_name, const LabelTranslator &translator)
Definition: TreeRead.cxx:847
AW_awar * source_tree_awar(AW_root *root)
Definition: TreeAdmin.cxx:36
#define AWAR_TREE_EXPORT_INCLUDE_BRANCHLENS
Definition: ad_trees.cxx:72
SizeAwareTree * get(size_t &different_species, GB_ERROR &error)
Definition: CT_ctree.hxx:79
AW_window * create_copy_window(AW_root *root, const Spec *spec)
Definition: TreeAdmin.cxx:232
char * name
Definition: TreeNode.h:226
static AW_window_simple * create_oneTreeSelection(AW_root *root, const char *winId, const char *winTitle, const char *helpFile, AW_awar *awar_displayed_tree)
Definition: ad_trees.cxx:621
AW_awar * map(const char *awarn)
Definition: AW_awar.cxx:521
void subtitle(const char *stitle)
Definition: arb_progress.h:321
GB_ERROR GB_write_security_delete(GBDATA *gbd, unsigned long level)
Definition: arbdb.cxx:1605
GBT_LEN sum_child_lengths() const
Definition: TreeNode.cxx:699
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1118
void remove_bootstrap()
Definition: TreeNode.cxx:646
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
ARB_edge counter_next() const
Definition: TreeNode.h:894
AW_root * get_root()
Definition: aw_window.hxx:362
#define TEST_EXPECT_SAVED_NEWICK(format, gb_main, treename, expected_newick)
Definition: test_unit.h:1484
#define NULp
Definition: cxxforward.h:116
GBDATA * gb_main
Definition: NT_local.h:37
ExportTreeType
Definition: ad_trees.cxx:167
static GB_ERROR sort_tree_by_other_tree(GBDATA *gb_main, TreeNode *tree, const char *other_tree)
Definition: ad_trees.cxx:1076
#define TEST_EXPECT_ERROR_CONTAINS(call, part)
Definition: test_unit.h:1114
CombinedPosInfo(const CombinedPosInfo &c1, const CombinedPosInfo &c2)
Definition: ad_trees.cxx:1012
GB_ERROR write_string(const char *aw_string)
#define TEST_EXPECT_DIFFERENT(expr, want)
Definition: test_unit.h:1301
static char * command
Definition: arb_a2ps.c:319
LabelQuoting
Definition: TreeWrite.h:18
const char * get_data() const
Definition: arb_strbuf.h:120
GB_ERROR NTREE_move_tree_info(GBDATA *gb_main, const char *tree_source, const char *tree_dest, const char *log_file, GroupTransferMode mode, GroupsToTransfer what, const GroupMatchScorer &scorer, const char *aci)
#define AWAR_MFURC_LENGTH_LIMIT
Definition: ad_trees.cxx:1117
const char * local_id(const char *id) const
Definition: AW_window.cxx:738
#define FALLTHROUGH
Definition: cxxforward.h:136
GBT_LEN get_branchlength() const
Definition: TreeNode.h:311
#define AWAR_TREE_EXPORT_INCLUDE_BOOTSTRAPS
Definition: ad_trees.cxx:71
GBDATA * GBT_find_tree(GBDATA *gb_main, const char *tree_name)
Definition: adtree.cxx:1052
GB_transaction ta(gb_var)
void callback(const WindowCallback &cb)
Definition: AW_window.cxx:142
#define AWAR_TREE_EXPORT_HIDE_FOLDED_GROUPS
Definition: ad_trees.cxx:74
void destroy(TreeNode *that)
Definition: TreeNode.h:667
GBDATA * gb_main
Definition: adname.cxx:32
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:622
void set_length(GBT_LEN len)
Definition: TreeNode.h:844
AW_window * aww
Definition: canvas.hxx:347
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
#define AWAR_TREE_EXPORT_FILEBASE
Definition: ad_trees.cxx:63
void hide_or_notify(const char *error)
Definition: AW_window.cxx:1838
void NT_deselect_group(AW_root *awr)
Definition: NT_extern.cxx:971
#define AWAR_TREE_SECURITY
Definition: ad_trees.cxx:45
static void sort_tree_by_other_tree_cb(UNFIXED, TREE_canvas *ntw)
Definition: ad_trees.cxx:1096
static void use_selected_as_target_cb(AW_window *aww)
Definition: ad_trees.cxx:957
#define AWAR_TREE_EXPORT_NON_ASCII
Definition: ad_trees.cxx:76
AW_awar * awar_pointer(const char *var_name, GBDATA *default_value=NULp, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:642
static AW_window * create_tree_import_window(AW_root *root)
Definition: ad_trees.cxx:471
AW_awar * get_awar_tree() const
CombinedPosInfo(const TreeRelativePosition &s, const TreeRelativePosition &t)
Definition: ad_trees.cxx:1006
TreeRelativePosition relative(const char *name) const
Definition: tree_position.h:78
#define AW_ROOT_DEFAULT
Definition: aw_base.hxx:106
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
AW_selection_list * get_sellist()
Definition: aw_select.hxx:196
GBDATA * GBT_tree_infrontof(GBDATA *gb_tree)
Definition: adtree.cxx:1090
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:655
NT_global GLOBAL
Definition: NT_main.cxx:47
TreeNode * source() const
Definition: TreeNode.h:834
BootstrapSaveStyle
Definition: TreeWrite.h:29
void put(char c)
Definition: arb_strbuf.h:179
void NT_multifurcate_tree(TREE_canvas *ntw, const TreeNode::multifurc_limits &below)
#define UNCOVERED()
Definition: arb_assert.h:380
Definition: arbdb.h:66
#define AWAR_GROUPXFER_OVERWRITE_MODE
Definition: ad_trees.cxx:52
GB_write_int const char s
Definition: AW_awar.cxx:154