ARB
selection_admin.cxx
Go to the documentation of this file.
1 // ========================================================= //
2 // //
3 // File : selection_admin.cxx //
4 // Purpose : species selection admin //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in Feb 26 //
7 // http://www.arb-home.de/ //
8 // //
9 // ========================================================= //
10 
11 #include "selection_admin.h"
12 #include <sel_boxes.hxx>
13 
14 #include <aw_select.hxx>
15 #include <aw_root.hxx>
16 #include <aw_awar.hxx>
17 #include <aw_awar_defs.hxx>
18 #include <aw_msg.hxx>
19 
20 #include <arb_global_defs.h>
21 #include <arb_strarray.h>
22 
23 #include <ad_config.h>
24 #include <ad_cb.h>
25 #include <arbdbt.h>
26 #include <RegExpr.hxx>
27 
28 #include <TreeNode.h>
29 #include <modules.hxx>
30 
31 #include <map>
32 
33 using namespace std;
34 
35 // -----------------------------
36 // class Store_species
37 
38 class Store_species : virtual Noncopyable {
39  // stores an amount of species:
40  TreeNode *node;
41  Store_species *next;
42 public:
44  node = aNode;
45  next = NULp;
46  }
47  ~Store_species();
48 
50  arb_assert(!next);
51  next = list;
52  return this;
53  }
54 
55  Store_species* remove() {
56  Store_species *follower = next;
57  next = NULp;
58  return follower;
59  }
60 
61  TreeNode *getNode() const { return node; }
62 
63  void call(void (*aPizza)(TreeNode*)) const;
64 };
65 
67  delete next;
68 }
69 
70 void Store_species::call(void (*aPizza)(TreeNode*)) const {
71  aPizza(node);
72  if (next) next->call(aPizza);
73 }
74 
75 // -----------------------------
76 
77 static void unmark_species(TreeNode *node) {
78  arb_assert(node);
79  arb_assert(node->gb_node);
80  arb_assert(GB_read_flag(node->gb_node)!=0);
81  GB_write_flag(node->gb_node, 0);
82 }
83 
84 static void mark_species(TreeNode *node, Store_species **extra_marked_species) {
85  arb_assert(node);
86  arb_assert(node->gb_node);
87  arb_assert(GB_read_flag(node->gb_node)==0);
88  GB_write_flag(node->gb_node, 1);
89 
90  *extra_marked_species = (new Store_species(node))->add(*extra_marked_species);
91 }
92 
94  arb_assert(node);
95  while (!node->is_leaf()) {
96  node = node->get_rightson();
97  arb_assert(node);
98  }
99  return node;
100 }
101 
103  if (node) {
104  TreeNode *father = node->get_father();
105  while (father) {
106  if (father->rightson==node) {
107  node = rightmost_leaf(father->get_leftson());
108  arb_assert(node->is_leaf());
109  if (!node->gb_node) { // Zombie
110  node = left_neighbour_leaf(node);
111  }
112  return node;
113  }
114  node = father;
115  father = node->get_father();
116  }
117  }
118  return NULp;
119 }
120 
121 const char CFG_SEP = 1;
122 
124  TreeNode *tree,
125  GBS_strstruct& memfile,
126  Store_species **extra_marked_species,
127  int use_species_aside,
128  int *auto_mark,
129  int marked_at_left,
130  int *marked_at_right)
131 {
163  if (!tree) return 0;
164  if (tree->is_leaf()) {
165  if (!tree->gb_node) {
166  UNCOVERED();
167  *marked_at_right = marked_at_left;
168  return 0; // Zombie
169  }
170 
171  if (!GB_read_flag(tree->gb_node)) { // unmarked species
172  if (*auto_mark) {
173  (*auto_mark)--;
174  mark_species(tree, extra_marked_species);
175  }
176  else {
177  *marked_at_right = 0;
178  return 0;
179  }
180  }
181  else { // marked species
182  if (marked_at_left<use_species_aside) {
183  // on the left side there are not as many marked species as needed!
184 
185  arb_assert(marked_at_left>=0);
186 
187  TreeNode *leaf_at_left = tree;
188  int step_over = marked_at_left+1; // step over myself
189  int then_mark = use_species_aside-marked_at_left;
190 
191  while (step_over--) { // step over self and over any adjacent, marked species
192  leaf_at_left = left_neighbour_leaf(leaf_at_left);
193  }
194 
195  Store_species *marked_back = NULp;
196  while (leaf_at_left && then_mark--) { // then additionally mark some species
197  if (GB_read_flag(leaf_at_left->gb_node) == 0) { // if they are not marked yet
198  mark_species(leaf_at_left, extra_marked_species);
199  marked_back = (new Store_species(leaf_at_left))->add(marked_back);
200  }
201  leaf_at_left = left_neighbour_leaf(leaf_at_left);
202  }
203 
204  while (marked_back) {
205  memfile.put(CFG_SEP);
206  memfile.put('L');
207  memfile.cat(marked_back->getNode()->name);
208  GBS_write_hash(used, marked_back->getNode()->name, 1); // Mark species
209 
210  Store_species *rest = marked_back->remove();
211  delete marked_back;
212  marked_back = rest;
213  }
214 
215  marked_at_left = use_species_aside;
216  }
217  // now use_species_aside species to left are marked!
218  *auto_mark = use_species_aside;
219  }
220 
221  memfile.put(CFG_SEP);
222  memfile.put('L');
223  memfile.cat(tree->name);
224  GBS_write_hash(used, tree->name, 1); // Mark species
225 
226  *marked_at_right = marked_at_left+1;
227  return 1;
228  }
229 
230  const size_t oldpos = memfile.get_position();
231  if (tree->gb_node && tree->name) { // but we are a group
232  GBDATA *gb_grouped = GB_entry(tree->gb_node, "grouped");
233  memfile.put(CFG_SEP);
234  if (gb_grouped && GB_read_byte(gb_grouped)) {
235  memfile.put('F');
236  }
237  else {
238  memfile.put('G');
239  }
240 
241  memfile.cat(tree->name);
242  }
243 
244  int right_of_leftson;
245  long nspecies= nt_build_conf_string_rek(used, tree->get_leftson(), memfile, extra_marked_species, use_species_aside, auto_mark, marked_at_left, &right_of_leftson);
246  nspecies += nt_build_conf_string_rek(used, tree->get_rightson(), memfile, extra_marked_species, use_species_aside, auto_mark, right_of_leftson, marked_at_right);
247 
248  if (tree->gb_node && tree->name) { // but we are a group
249  memfile.put(CFG_SEP);
250  memfile.put('E'); // Group end indicated by 'E'
251  }
252 
253  if (!nspecies) {
254  const size_t newpos = memfile.get_position();
255  memfile.cut_tail(newpos-oldpos); // delete group info
256  }
257  return nspecies;
258 }
259 
262  const char *last_group_name;
263 };
264 
265 static void nt_build_sai_string_by_hash(const char *key, long /*val*/, void *cd_sai_builder) {
266  SAI_string_builder *sai_builder = (SAI_string_builder*)cd_sai_builder;
267 
268  const char *sep = strchr(key, 1);
269  if (sep) {
270  GBS_strstruct& sai_middle = sai_builder->sai_middle;
271  const char *last_group_name = sai_builder->last_group_name;
272 
273  if (!last_group_name || strncmp(key, last_group_name, sep-key)) { // new group
274  if (last_group_name) {
275  sai_middle.put(CFG_SEP);
276  sai_middle.put('E'); // End of old group
277  }
278  sai_middle.put(CFG_SEP);
279  sai_middle.cat("FSAI:");
280  sai_middle.ncat(key, sep-key);
281  sai_builder->last_group_name = key;
282  }
283  sai_middle.put(CFG_SEP);
284  sai_middle.put('S');
285  sai_middle.cat(sep+1);
286  }
287 }
288 
289 static void nt_build_sai_string(GBDATA *gb_main, const char *topAreaSaiList, GBS_strstruct& topfile, GBS_strstruct& middlefile) {
290  // collect all Sais,
291  // place some SAI in top area (those listed in 'toparea_SAIs'. SAI-groups will be ignored here)
292  // rest of SAI goes into middle area (SAI-groups respected here)
293 
294  GBDATA *gb_sai_data = GBT_get_SAI_data(gb_main);
295  if (gb_sai_data) {
297 
298  ConstStrArray topAreaSai;
299  GBT_split_string(topAreaSai, topAreaSaiList, ",;: \t", SPLIT_DROPEMPTY);
300 
301  for (GBDATA *gb_sai = GBT_first_SAI_rel_SAI_data(gb_sai_data); gb_sai; gb_sai = GBT_next_SAI(gb_sai)) {
302  GBDATA *gb_name = GB_search(gb_sai, "name", GB_FIND);
303  if (gb_name) {
304  char *name = GB_read_string(gb_name);
305 
306  bool wantedInTop = false;
307  for (unsigned s = 0; !wantedInTop && s<topAreaSai.size(); ++s) {
308  wantedInTop = strcmp(name, topAreaSai[s]) == 0;
309  }
310 
311  if (!wantedInTop) {
312  GBDATA *gb_gn = GB_search(gb_sai, "sai_group", GB_FIND);
313  char *gn;
314 
315  if (gb_gn) gn = GB_read_string(gb_gn);
316  else gn = ARB_strdup("SAI's");
317 
318  char *cn = new char[strlen(gn) + strlen(name) + 2];
319  sprintf(cn, "%s%c%s", gn, 1, name);
320  GBS_write_hash(hash, cn, 1);
321  delete [] cn;
322  free(gn);
323  }
324  free(name);
325  }
326  }
327 
328  // add top area SAIs in defined order:
329  for (unsigned s = 0; s<topAreaSai.size(); ++s) {
330  GBDATA *gb_sai = GBT_find_SAI_rel_SAI_data(gb_sai_data, topAreaSai[s]);
331  if (gb_sai) {
332  topfile.put(CFG_SEP);
333  topfile.put('S');
334  topfile.cat(topAreaSai[s]);
335  }
336  }
337 
338  // open surrounding SAI-group:
339  middlefile.put(CFG_SEP);
340  middlefile.cat("GSAI-Maingroup");
341 
342  SAI_string_builder sai_builder = { middlefile, NULp };
344  if (sai_builder.last_group_name) {
345  middlefile.put(CFG_SEP);
346  middlefile.put('E'); // End of old group
347  }
348 
349  // close surrounding SAI-group:
350  middlefile.put(CFG_SEP);
351  middlefile.put('E');
352 
353  GBS_free_hash(hash);
354  }
355 }
356 
358  file.put(CFG_SEP);
359  file.cat("FMore Sequences");
360 
361  for (GBDATA *gb_species = GBT_first_marked_species(gb_main);
362  gb_species;
363  gb_species = GBT_next_marked_species(gb_species))
364  {
365  char *name = GBT_read_string(gb_species, "name");
366  if (!GBS_read_hash(used, name)) {
367  file.put(CFG_SEP);
368  file.put('L');
369  file.cat(name);
370  }
371  free(name);
372  }
373 
374  file.put(CFG_SEP);
375  file.put('E'); // Group end indicated by 'E'
376 }
377 
378 void extract_species_selection(GBDATA *gb_main, const char *selectionName, SelectionExtractType ext_type) {
379  GB_transaction ta(gb_main);
380  AW_root *aw_root = AW_root::SINGLETON;
381 
382  if (strcmp(selectionName, NO_CONFIG_SELECTED) == 0) {
383  aw_message("Please select a configuration");
384  }
385  else {
386  GB_ERROR error = NULp;
387  GBT_config cfg(gb_main, selectionName, error);
388 
389  if (!error) {
390  size_t unknown_species = 0;
391  bool refresh = false;
392 
393  GB_HASH *was_marked = NULp; // only used for SELECTION_COMBINE
394 
395  switch (ext_type) {
396  case SELECTION_EXTRACT: // unmark all
397  GBT_mark_all(gb_main, 0);
398  refresh = true;
399  break;
400 
401  case SELECTION_COMBINE: // store all marked species in hash and unmark them
402  was_marked = GBT_create_marked_species_hash(gb_main);
403  GBT_mark_all(gb_main, 0);
404  refresh = GBS_hash_elements(was_marked);
405  break;
406 
407  default:
408  break;
409  }
410 
411  for (int area = 0; area<=1 && !error; ++area) {
412  GBT_config_parser cparser(cfg, area);
413 
414  while (1) {
415  const GBT_config_item& citem = cparser.nextItem(error);
416  if (error || citem.type == CI_END_OF_CONFIG) break;
417 
418  if (citem.type == CI_SPECIES) {
419  GBDATA *gb_species = GBT_find_species(gb_main, citem.name);
420 
421  if (gb_species) {
422  int oldmark = GB_read_flag(gb_species);
423  int newmark = oldmark;
424  switch (ext_type) {
425  case SELECTION_EXTRACT:
426  case SELECTION_MARK: newmark = 1; break;
427  case SELECTION_UNMARK: newmark = 0; break;
428  case SELECTION_INVERT: newmark = !oldmark; break;
429  case SELECTION_COMBINE: {
430  arb_assert(!oldmark); // should have been unmarked above
431  newmark = GBS_read_hash(was_marked, citem.name); // mark if was_marked
432  break;
433  }
434  default: arb_assert(0); break;
435  }
436  if (newmark != oldmark) {
437  GB_write_flag(gb_species, newmark);
438  refresh = true;
439  }
440  }
441  else {
442  unknown_species++;
443  }
444  }
445  }
446  }
447 
448  if (was_marked) GBS_free_hash(was_marked);
449  if (unknown_species>0 && !error) error = GBS_global_string("configuration '%s' contains %zu unknown species", selectionName, unknown_species);
450  if (refresh) aw_root->awar(AWAR_TREE_REFRESH)->touch();
451  }
452  aw_message_if(error);
453  }
454 }
455 
456 static void nt_extract_configuration(UNFIXED, const SelectionAdmin *selection, SelectionExtractType ext_type) {
457  GBDATA *gb_main = selection->get_gb_main();
458  AW_root *aw_root = AW_root::SINGLETON;
459 
460  char *selectionName = aw_root->awar(selection->get_selection_awarname())->read_string();
461  extract_species_selection(gb_main, selectionName, ext_type);
462  free(selectionName);
463 }
464 
465 static void nt_delete_configuration(AW_window *aww, AW_DB_selection *dbsel, const SelectionAdmin *selection) {
466  GBDATA *gb_main = selection->get_gb_main();
467  GB_transaction ta(gb_main);
468 
469  AW_awar *awar_selected = aww->get_root()->awar(selection->get_selection_awarname());
470  char *name = awar_selected->read_string();
471  GBDATA *gb_configuration = GBT_find_configuration(gb_main, name);
472 
473  if (gb_configuration) {
474  dbsel->get_sellist()->move_selection(1);
475 
476  GB_ERROR error = GB_delete(gb_configuration);
477  error = ta.close(error);
478  if (error) {
479  aw_message(error);
480  }
481  else {
482  selection->speciesSelection_deleted_cb(name);
483  }
484  }
485  free(name);
486 }
487 
488 static void selected_config_changed_cb(AW_root *root, const SelectionAdmin *selection) {
489  const char *config = root->awar(selection->get_selection_awarname())->read_char_pntr();
490 
491  bool nonexisting_config = false;
492  GBDATA *gb_target_commment = NULp;
493  if (config[0]) {
494  GBDATA *gb_configuration = GBT_find_configuration(selection->get_gb_main(), config);
495  if (gb_configuration) {
496  gb_target_commment = GB_entry(gb_configuration, "comment");
497  }
498  else {
499  nonexisting_config = true;
500  }
501  }
502 
503  AW_awar *awar_comment = root->awar(selection->get_selectionComment_awarname());
504  if (gb_target_commment) {
505  if (!awar_comment->is_mapped()) awar_comment->write_string("");
506  awar_comment->map(gb_target_commment);
507  }
508  else {
509  char *reuse_comment = nonexisting_config ? awar_comment->read_string() : ARB_strdup("");
510  if (awar_comment->is_mapped()) {
511  awar_comment->unmap();
512  }
513  awar_comment->write_string(reuse_comment);
514  free(reuse_comment);
515  }
516 }
517 static void config_comment_changed_cb(AW_root *root, const SelectionAdmin *selection) {
518  // called when comment-awar changes or gets re-map-ped
519 
520  AW_awar *awar_comment = root->awar(selection->get_selectionComment_awarname());
521  const char *comment = awar_comment->read_char_pntr();
522 
523  const char *config = root->awar(selection->get_selection_awarname())->read_char_pntr();
524  GBDATA *gb_configuration = config[0] ? GBT_find_configuration(selection->get_gb_main(), config) : NULp;
525 
526  GB_ERROR error = NULp;
527  if (awar_comment->is_mapped()) {
528  if (!comment[0]) { // empty existing comment
529  arb_assert(gb_configuration);
530  GBDATA *gb_commment = GB_entry(gb_configuration, "comment");
531  arb_assert(gb_commment);
532  if (gb_commment) {
533  awar_comment->unmap();
534  error = GB_delete(gb_commment);
535  }
536  }
537  }
538  else {
539  if (comment[0]) { // ignore empty comment for unmapped awar
540  if (gb_configuration) {
541  arb_assert(!GB_entry(gb_configuration, "comment"));
542  error = GBT_write_string(gb_configuration, "comment", comment);
543  if (!error) {
544  awar_comment->write_string("");
545  selected_config_changed_cb(root, selection);
546  }
547  }
548  else if (!config[0]) {
549  // do NOT warn if name field contains (not yet) existing name
550  // (allows to edit comment while creating new config)
551  error = "Please select an existing species selection to edit its comment";
552  }
553  }
554  }
555 
556  aw_message_if(error);
557 }
558 static void init_awars_and_callbacks(AW_root *awr, const SelectionAdmin *selection, bool install_callbacks) {
559  AW_awar *awar_selection = awr->awar_string(selection->get_selection_awarname(), DEFAULT_CONFIGURATION, selection->get_gb_main());
560  AW_awar *awar_comment = awr->awar_string(selection->get_selectionComment_awarname(), "", selection->get_gb_main());
561 
562  typedef map<AW_awar*, AW_awar*> CorrespondingAwarMap;
563  static CorrespondingAwarMap corresponding;
564  typedef CorrespondingAwarMap::iterator CorrespondingIter;
565 
566  CorrespondingIter corr_selection = corresponding.find(awar_selection);
567  CorrespondingIter corr_comment = corresponding.find(awar_comment);
568 
569  if (corr_selection == corr_comment) {
570  arb_assert(corr_selection == corresponding.end()); // otherwise awars are identical (BUG)
571 
572  if (install_callbacks) {
573  // both are not found -> install callbacks (happens once)
574  awar_comment->add_callback(makeRootCallback(config_comment_changed_cb, selection));
575  awar_selection->add_callback(makeRootCallback(selected_config_changed_cb, selection))->touch();
576 
577  // register both awars as "corresponding":
578  corresponding[awar_comment] = awar_selection;
579  corresponding[awar_selection] = awar_comment;
580  }
581  }
582 #if defined(ASSERTION_USED)
583  else {
584  // expect that both are mapped to each other (otherwise comment editing may behave unexpected!)
585  arb_assert(corr_selection != corresponding.end() && corr_selection->second == awar_comment);
586  arb_assert(corr_comment != corresponding.end() && corr_comment->second == awar_selection);
587  }
588 #endif
589 }
590 
591 GB_ERROR create_species_selection(const SelectionAdmin& selection, const char *conf_name, int use_species_aside, SelectionCreation creation) {
592  GB_ERROR error = NULp;
593 
594  if (!conf_name || !conf_name[0]) error = "no config name given";
595  else {
596  if (use_species_aside==-1) {
597  static int last_used_species_aside = 3;
598  {
599  const char *val = GBS_global_string("%i", last_used_species_aside);
600  char *use_species = aw_input("How many extra species to view aside marked:", val);
601  if (use_species) use_species_aside = atoi(use_species);
602  free(use_species);
603  }
604 
605  if (use_species_aside<1) error = "illegal number of 'species aside'";
606  else last_used_species_aside = use_species_aside; // remember for next time
607  }
608 
609  if (!error) {
611  GBDATA *gb_main = selection.get_gb_main();
612  TreeNode *tree = selection.get_tree_root(); // nullable
613 
614  init_awars_and_callbacks(awr, &selection, false); // Warning: only creates awars. It's not possible to install callbacks here (selection is an auto variable!)
615 
616  GB_transaction ta(gb_main); // open close transaction
617 
618  GBT_config newcfg;
619  {
621  GBS_strstruct topfile(1000);
622  GBS_strstruct midfile(10000);
623  {
624  GBS_strstruct middlefile(10000);
625  nt_build_sai_string(gb_main, selection.get_toparea_SAIs(), topfile, midfile);
626 
627  if (use_species_aside) {
628  Store_species *extra_marked_species = NULp;
629  int auto_mark = 0;
630  int marked_at_right;
631 
632  nt_build_conf_string_rek(used, tree, middlefile, &extra_marked_species, use_species_aside, &auto_mark, use_species_aside, &marked_at_right);
633  if (extra_marked_species) {
634  extra_marked_species->call(unmark_species);
635  delete extra_marked_species;
636  }
637  }
638  else {
639  int dummy_1=0, dummy_2;
640  nt_build_conf_string_rek(used, tree, middlefile, NULp, 0, &dummy_1, 0, &dummy_2);
641  }
642  nt_build_conf_marked(gb_main, used, midfile);
643  midfile.ncat(middlefile.get_data(), middlefile.get_position());
644  }
645 
646  newcfg.set_definition(GBT_config::TOP_AREA, topfile.release());
648 
649  GBS_free_hash(used);
650  }
651 
652  GBT_config previous(gb_main, conf_name, error);
653  error = NULp; // ignore
654 
655  const char *prevComment = NULp; // old or fixed comment
656  const char *comment = NULp;
657  bool warnIfSavingDefault = true;
658  switch (creation) {
659  case BY_CALLING_THE_EDITOR: { // always saves DEFAULT_CONFIGURATION!
660  prevComment = "This configuration will be OVERWRITTEN each time\nARB_EDIT4 is started w/o specifying a config!\n---";
661  comment = "created for ARB_EDIT4";
662  warnIfSavingDefault = false;
663  break;
664  }
665  case FROM_MANAGER: {
666  if (previous.exists()) {
667  prevComment = previous.get_comment();
668  comment = "updated manually";
669  }
670  else {
671  prevComment = awr->awar(selection.get_selectionComment_awarname())->read_char_pntr();
672  comment = "created manually";
673  }
674  break;
675  }
676  case FROM_IMPORTER: {
677  arb_assert(!previous.exists());
678  comment = "created by importer";
679  break;
680  }
681  }
682 
683  if (prevComment && !prevComment[0]) prevComment = NULp; // handle empty comment like "no comment"
684 
685  arb_assert(implicated(prevComment, comment));
686  if (comment) {
687  // annotate comment with treename
688  if (tree) {
689  const char *treename = selection.get_name_of_tree();
690  comment = GBS_global_string("%s (tree=%s)", comment, treename);
691  }
692  else {
693  comment = GBS_global_string("%s (no tree)", comment);
694  }
695  char *dated = GBS_log_action_to(prevComment, comment, true);
696  newcfg.set_comment(dated);
697  free(dated);
698  }
699 
700  error = newcfg.save(gb_main, conf_name, warnIfSavingDefault);
701  awr->awar(selection.get_selection_awarname())->touch(); // refreshes comment field
702  }
703  }
704 
705  return error;
706 }
707 
708 static void nt_store_configuration(AW_window*, const SelectionAdmin *selection) {
709  const char *cfgName = AW_root::SINGLETON->awar(selection->get_selection_awarname())->read_char_pntr();
710  GB_ERROR err = create_species_selection(*selection, cfgName, 0, FROM_MANAGER);
711  aw_message_if(err);
712 }
713 
714 static void nt_rename_configuration(AW_window *aww, const SelectionAdmin *selection) {
715  AW_awar *awar_curr_cfg = aww->get_root()->awar(selection->get_selection_awarname());
716 
717  char *old_name = awar_curr_cfg->read_string();
718  char *new_name = aw_input("Rename selection", "Enter the new name of the selection", old_name);
719 
720  if (new_name) {
721  GB_ERROR err = NULp;
722  GBDATA *gb_main = selection->get_gb_main();
723 
724  {
725  GB_transaction ta(gb_main);
726 
727  GBDATA *gb_existing_cfg = GBT_find_configuration(gb_main, new_name);
728  if (gb_existing_cfg) err = GBS_global_string("There is already a selection named '%s'", new_name);
729  else {
730  GBDATA *gb_old_cfg = GBT_find_configuration(gb_main, old_name);
731  if (gb_old_cfg) {
732  GBDATA *gb_name = GB_entry(gb_old_cfg, "name");
733  if (gb_name) {
734  err = GB_write_string(gb_name, new_name);
735  if (!err) awar_curr_cfg->write_string(new_name);
736  }
737  else err = "Selection has no name";
738  }
739  else err = "Can't find that selection";
740  }
741  err = ta.close(err);
742  }
743 
744  if (err) {
745  aw_message(err);
746  }
747  else {
748  arb_assert(GB_get_transaction_level(gb_main) == 0); // otherwise callback below behaves wrong
749  selection->speciesSelection_renamed_cb(old_name, new_name);
750  }
751  free(new_name);
752  }
753  free(old_name);
754 }
755 
756 #pragma GCC diagnostic push
757 #if (GCC_VERSION_CODE<700)
758 #pragma GCC diagnostic ignored "-Wstrict-overflow" // gcc 6.x produces a bogus overflow warning (gcc 7.x is smart enough)
759 #endif
760 
761 static GB_ERROR swap_configs(GBDATA *gb_main, StrArray& config, int i1, int i2) {
762  GB_ERROR error = NULp;
763 
764  if (i1>i2) swap(i1, i2); // otherwise overwrite below does not work
765  arb_assert(i1<i2 && i1>=0 && i2<int(config.size()));
766 
767  GBT_config c1(gb_main, config[i1], error);
768  if (!error) {
769  GBT_config c2(gb_main, config[i2], error);
770  if (!error) error = c1.saveAsOver(gb_main, config[i1], config[i2], false);
771  if (!error) error = c2.saveAsOver(gb_main, config[i2], config[i1], false);
772  if (!error) config.swap(i1, i2);
773  }
774  return error;
775 }
776 
777 #pragma GCC diagnostic pop
778 
780  AW_root *awr = aww->get_root();
781  AW_selection_list *sellist = sel->get_sellist();
782  AW_awar *awar_config = awr->awar(sellist->get_awar_name());
783  const char *selected = awar_config->read_char_pntr();
784 
785  if (selected && selected[0]) {
786  int source_idx = sellist->get_index_of(AW_scalar(selected));
787  int target_idx = -1;
788  switch (mode) {
789  case ARM_TOP: target_idx = 0; break;
790  case ARM_UP: target_idx = source_idx-1; break;
791  case ARM_DOWN: target_idx = source_idx+1; break;
792  case ARM_BOTTOM: target_idx = -1; break;
793  }
794 
795  int entries = sellist->size();
796  target_idx = (target_idx+entries)%entries;
797 
798  {
799  GBDATA *gb_main = sel->get_gb_main();
800  GB_transaction ta(gb_main);
801 
802  StrArray config;
803  sellist->to_array(config, true);
804 
805  GB_ERROR error = NULp;
806  if (source_idx<target_idx) {
807  for (int i = source_idx+1; i<=target_idx; ++i) {
808  swap_configs(gb_main, config, i-1, i);
809  }
810  }
811  else if (source_idx>target_idx) {
812  for (int i = source_idx-1; i>=target_idx; --i) {
813  swap_configs(gb_main, config, i+1, i);
814  }
815  }
816 
817  error = ta.close(error);
818  aw_message_if(error);
819  }
820  awar_config->touch();
821  }
822 }
823 
824 static void clear_comment_cb(AW_window *aww, const SelectionAdmin *selection) {
825  AW_awar *awar_comment = aww->get_root()->awar(selection->get_selectionComment_awarname());
826  char *comment = awar_comment->read_string();
827 
829  GBT_splitNdestroy_string(line, comment, '\n');
830 
831  bool removedDatedLines = false;
832  RegExpr datedLine("^([A-Z][a-z]{2}\\s){2}[0-9]+\\s([0-9]{2}:){2}[0-9]{2}\\s[0-9]{4}:\\s", false); // matches lines created with GBS_log_action_to(..., stamp=true)
833  for (int i = line.size()-1; i >= 0; --i) {
834  const RegMatch *match = datedLine.match(line[i]);
835  arb_assert(implicated(!match, !datedLine.has_failed())); // assert RegExpr compiles
836  if (match && match->didMatch()) {
837  line.safe_remove(i);
838  removedDatedLines = true;
839  }
840  }
841 
842  if (!removedDatedLines) line.clear(); // erase all
843 
844  comment = GBT_join_strings(line, '\n');
845  awar_comment->write_string(comment);
846 }
847 
848 static void update_marked_counter_label(GBDATA *gb_species_data, AW_awar *awar_counter_label) {
853  GBDATA *gb_main = GB_get_root(gb_species_data);
854  long count = GBT_count_marked_species(gb_main);
855  const char *buffer = count ? GBS_global_string("%li marked", count) : "";
856 
857  if (strcmp(awar_counter_label->read_char_pntr(), buffer)) {
858  awar_counter_label->write_string(buffer);
859  awr->awar(AWAR_TREE_REFRESH)->touch();
860  }
861 }
862 
863 void create_species_selection_button(AW_window *awm, WindowCallback wcb, const char *macro_id, const char *awarname_buttontext, GBDATA *gb_main) {
864  awm->button_length(13);
865  awm->help_text("species_configs.hlp");
866  awm->callback(wcb);
867 
868  AW_root *awr = awm->get_root();
869  AW_awar *awar_counter_label = awr->awar_string(awarname_buttontext, "unknown", gb_main);
870 
871  awm->create_button(macro_id, awarname_buttontext);
872  {
873  GB_transaction ta(gb_main);
874 
876  DatabaseCallback dbcb = makeDatabaseCallback(update_marked_counter_label, awar_counter_label);
877 
878  aw_message_if(GB_ensure_callback(gb_species_data, GB_CB_CHANGED, dbcb));
879  dbcb(gb_species_data, GB_CB_CHANGED);
880  }
881 }
882 
884  init_awars_and_callbacks(root, selection, true);
885 
886  AW_window_simple *aws = new AW_window_simple;
887 
888  aws->init(root, GBS_global_string("SPECIES_SELECTIONS_%s", selection->get_macro_suffix()), selection->get_window_title());
889  aws->load_xfig("nt_selection.fig");
890 
891  aws->at("close");
892  aws->callback(AW_POPDOWN);
893  aws->create_button("CLOSE", "CLOSE", "C");
894 
895  aws->at("help");
896  aws->callback(makeHelpCallback("species_configs.hlp"));
897  aws->create_button("HELP", "HELP", "H");
898 
899  aws->at("name");
900  aws->create_input_field(selection->get_selection_awarname());
901 
902  aws->at("comment");
903  aws->create_text_field(selection->get_selectionComment_awarname());
904 
905  aws->at("clr");
906  aws->callback(makeWindowCallback(clear_comment_cb, selection));
907  aws->create_autosize_button("CLEAR", "Clear", "l");
908 
909  aws->at("list");
911 
912  aws->button_length(8);
913 
914  aws->at("store");
915  aws->callback(makeWindowCallback(nt_store_configuration, selection));
916  {
917  const char *new_id = "STORE";
918  aws->create_button(new_id, "STORE", "S");
919 
920  // provide intermediate backward compatibility for old, unwanted ID:
921  const char *old_id = GBS_global_string("STORE_%s", selection->get_macro_suffix());
922  aws->alias_remote_command(old_id, new_id);
923  }
924 
925  aws->at("extract");
926  aws->callback(makeWindowCallback(nt_extract_configuration, selection, SELECTION_EXTRACT));
927  aws->create_button("EXTRACT", "EXTRACT", "E");
928 
929  aws->at("mark");
930  aws->callback(makeWindowCallback(nt_extract_configuration, selection, SELECTION_MARK));
931  aws->create_button("MARK", "MARK", "M");
932 
933  aws->at("unmark");
934  aws->callback(makeWindowCallback(nt_extract_configuration, selection, SELECTION_UNMARK));
935  aws->create_button("UNMARK", "UNMARK", "U");
936 
937  aws->at("invert");
938  aws->callback(makeWindowCallback(nt_extract_configuration, selection, SELECTION_INVERT));
939  aws->create_button("INVERT", "INVERT", "I");
940 
941  aws->at("combine");
942  aws->callback(makeWindowCallback(nt_extract_configuration, selection, SELECTION_COMBINE));
943  aws->create_button("COMBINE", "COMBINE", "C");
944 
945  aws->at("delete");
946  aws->callback(makeWindowCallback(nt_delete_configuration, dbsel, selection));
947  aws->create_button("DELETE", "DELETE", "D");
948 
949  aws->at("rename");
950  aws->callback(makeWindowCallback(nt_rename_configuration, selection));
951  aws->create_button("RENAME", "RENAME", "R");
952 
953  aws->button_length(0);
954  aws->at("sort");
956 
957  return aws;
958 }
959 
960 // --------------------------------------------------------------------------------
961 
962 #ifdef UNIT_TESTS
963 #ifndef TEST_UNIT_H
964 #include <test_unit.h>
965 #endif
966 
967 static bool fold_group(TreeNode *tree, const char *groupName) {
968  if (!tree->is_leaf()) {
969  if (tree->is_normal_group()) {
970  arb_assert(tree->name);
971  fprintf(stderr, "group='%s' groupName='%s'\n", tree->name, groupName);
972  if (strcmp(tree->name, groupName) == 0) {
973  arb_assert(tree->gb_node);
974  GBDATA *gb_grouped = GB_entry(tree->gb_node, "grouped");
975  if (!gb_grouped) {
976  gb_grouped = GB_create(tree->gb_node, "grouped", GB_BYTE);
977  }
978  TEST_REJECT_NULL(gb_grouped);
979  if (GB_read_byte(gb_grouped) == 0) {
980  TEST_EXPECT_NO_ERROR(GB_write_byte(gb_grouped, 1));
981  return true;
982  }
983  }
984  }
985  return
986  fold_group(tree->get_leftson(), groupName) ||
987  fold_group(tree->get_rightson(), groupName);
988  }
989  return false;
990 }
991 
992 void TEST_build_conf_string() {
993  GB_shell shell;
994  GBDATA *gb_main = GB_open("TEST_trees.arb", "r");
995 
996  {
997  GB_transaction ta(gb_main);
998 
999  TreeNode *tree = GBT_read_tree(gb_main, "tree_groups", new SimpleRoot);
1000 
1001  GBS_strstruct memfile(500);
1002  Store_species *extra_marked_species = NULp;
1003 
1004  TEST_REJECT_NULL(tree);
1005  TEST_EXPECT_NO_ERROR(GBT_link_tree(tree, gb_main, false, NULp, NULp));
1006 
1007  int auto_mark = 0;
1008  int dummy;
1009  int marked;
1010 
1011  // test result with no species marked:
1012  GBT_mark_all(gb_main, 0);
1014  {
1015  GB_HASH *used = GBS_create_hash(100, GB_IGNORE_CASE);
1016 
1017  memfile.erase();
1018  marked = nt_build_conf_string_rek(used, tree, memfile, &extra_marked_species, 0, &auto_mark, 0, &dummy);
1019  TEST_EXPECT_EQUAL(marked, 0);
1020  TEST_EXPECT_EQUAL(memfile.get_data(), "");
1021  TEST_EXPECT_NULL(extra_marked_species);
1022 
1024  GBS_free_hash(used);
1025  }
1026 
1027  // mark some species:
1028  TEST_EXPECT_NO_ERROR(GBT_restore_marked_species(gb_main, "CloButy2;CloPaste;CorAquat;CurCitre;CloTyro4"));
1030 
1031  {
1032  GB_HASH *used = GBS_create_hash(100, GB_IGNORE_CASE);
1033 
1034  memfile.erase();
1035  marked = nt_build_conf_string_rek(used, tree, memfile, &extra_marked_species, 0, &auto_mark, 0, &dummy);
1036  TEST_EXPECT_EQUAL(marked, 5); // ------------------------------------- v 'G' indicates the open group
1037  TEST_EXPECT_EQUAL(memfile.get_data(), "\1Gupper\1LCloButy2\1E\1Glower\1Glow1\1LCurCitre\1LCorAquat\1LCloPaste\1E\1Glow2\1LCloTyro4\1E\1E");
1038  TEST_EXPECT_NULL(extra_marked_species);
1039 
1041  GBS_free_hash(used);
1042  }
1043 
1044  // test with closed groups:
1045  {
1046  GB_HASH *used = GBS_create_hash(100, GB_IGNORE_CASE);
1047 
1048  TEST_EXPECT(fold_group(tree, "low1"));
1049 
1050  memfile.erase();
1051  marked = nt_build_conf_string_rek(used, tree, memfile, &extra_marked_species, 0, &auto_mark, 0, &dummy);
1052  TEST_EXPECT_EQUAL(marked, 5); // ------------------------------------- v 'F' indicates the closed group
1053  TEST_EXPECT_EQUAL(memfile.get_data(), "\1Gupper\1LCloButy2\1E\1Glower\1Flow1\1LCurCitre\1LCorAquat\1LCloPaste\1E\1Glow2\1LCloTyro4\1E\1E");
1054  TEST_EXPECT_NULL(extra_marked_species);
1055 
1057  GBS_free_hash(used);
1058  }
1059 
1060  // test with marking 2 species aside:
1061  {
1062  GB_HASH *used = GBS_create_hash(100, GB_IGNORE_CASE);
1063 
1064  memfile.erase();
1065  marked = nt_build_conf_string_rek(used, tree, memfile, &extra_marked_species, 2, &auto_mark, 0, &dummy);
1066  TEST_EXPECT_EQUAL(marked, 11);
1067  TEST_EXPECT_EQUAL(memfile.get_data(), "\1Gupper\1LCloTyro3\1LCloButyr\1LCloButy2\1LCloBifer\1LCloInnoc\1E\1Glower\1Flow1\1LCytAquat\1LCurCitre\1LCorAquat\1LCelBiazo\1LCorGluta\1LCloCarni\1LCloPaste\1E\1Glow2\1Gtwoleafs\1LCloTyrob\1LCloTyro2\1E\1LCloTyro4\1E\1E");
1068 
1069  TEST_REJECT_NULL(extra_marked_species);
1070  TEST_EXPECT_EQUAL(GBT_count_marked_species(gb_main), 15); // 5 species were marked before + marked 5*2 neighbors
1071  extra_marked_species->call(unmark_species);
1072  delete extra_marked_species;
1073  TEST_EXPECT_EQUAL(GBT_count_marked_species(gb_main), 5); // 5 previously marked species
1074 
1076  GBS_free_hash(used);
1077  }
1078 
1079  // test nt_build_conf_marked:
1080  {
1081  GB_HASH *used = GBS_create_hash(100, GB_IGNORE_CASE);
1082 
1083  memfile.erase();
1084  nt_build_conf_marked(gb_main, used, memfile);
1085  TEST_EXPECT_EQUAL(memfile.get_data(), "\1FMore Sequences\1LCorAquat\1LCurCitre\1LCloButy2\1LCloPaste\1LCloTyro4\1E");
1086 
1087  // exclude 2 species (simulates that they are already in "normal" config)
1088  GBS_write_hash(used, "CurCitre", 1);
1089  GBS_write_hash(used, "CloPaste", 1);
1090  memfile.erase();
1091  nt_build_conf_marked(gb_main, used, memfile);
1092  TEST_EXPECT_EQUAL(memfile.get_data(), "\1FMore Sequences\1LCorAquat\1LCloButy2\1LCloTyro4\1E");
1093 
1094  GBS_free_hash(used);
1095  }
1096 
1097  // test nt_build_sai_string:
1098  {
1099  GBS_strstruct topfile(500);
1100 
1101  memfile.erase();
1102  nt_build_sai_string(gb_main, "HELIX_NR;HELIX;dummy", topfile, memfile);
1103 
1104  TEST_EXPECT_EQUAL(topfile.get_data(), "\1SHELIX_NR\1SHELIX");
1105  TEST_EXPECT_EQUAL(memfile.get_data(), "\1GSAI-Maingroup\1FSAI:SAI's\1SPOS_VAR_BY_PARSIMONY\1E\1FSAI:special\1SECOLI\1E\1E");
1106  }
1107 
1108  destroy(tree);
1109  }
1110 
1111  GB_close(gb_main);
1112 }
1113 
1114 #endif // UNIT_TESTS
1115 
1116 // --------------------------------------------------------------------------------
1117 
1118 
GB_HASH * GBT_create_marked_species_hash(GBDATA *gb_main)
Definition: adhashtools.cxx:40
#define arb_assert(cond)
Definition: arb_assert.h:245
void GBS_hash_do_const_sorted_loop(const GB_HASH *hs, gb_hash_const_loop_type func, gbs_hash_compare_function sorter, void *client_data)
Definition: adhash.cxx:641
const char * GB_ERROR
Definition: arb_core.h:25
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
static void init_awars_and_callbacks(AW_root *awr, const SelectionAdmin *selection, bool install_callbacks)
void cut_tail(size_t byte_count)
Definition: arb_strbuf.h:145
virtual const char * get_selection_awarname() const =0
void button_length(int length)
Definition: AW_at.cxx:288
GBDATA * GBT_first_marked_species(GBDATA *gb_main)
Definition: aditem.cxx:113
size_t size() const
Definition: arb_strarray.h:85
Store_species(TreeNode *aNode)
Definition: arbdb.h:65
#define implicated(hypothesis, conclusion)
Definition: arb_assert.h:289
long GBS_write_hash(GB_HASH *hs, const char *key, long val)
Definition: adhash.cxx:454
GB_ERROR GBT_restore_marked_species(GBDATA *gb_main, const char *stored_marked)
Definition: aditem.cxx:446
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1387
long GBT_mark_all(GBDATA *gb_main, int flag)
Definition: aditem.cxx:295
static const int MIDDLE_AREA
Definition: ad_config.h:49
const char CFG_SEP
Store_species * add(Store_species *list)
void add(int v)
Definition: ClustalV.cxx:461
virtual const char * get_name_of_tree() const =0
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
TreeNode * GBT_read_tree(GBDATA *gb_main, const char *tree_name, TreeRoot *troot)
Definition: adtree.cxx:837
virtual void speciesSelection_deleted_cb(const char *name) const =0
static const int TOP_AREA
Definition: ad_config.h:48
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
static void nt_delete_configuration(AW_window *aww, AW_DB_selection *dbsel, const SelectionAdmin *selection)
STL namespace.
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
char * release()
Definition: arb_strbuf.h:129
void GBS_free_hash(GB_HASH *hs)
Definition: adhash.cxx:538
TreeNode * getNode() const
void cat(const char *from)
Definition: arb_strbuf.h:199
static void unmark_species(TreeNode *node)
bool is_mapped() const
Definition: aw_awar.hxx:153
GB_ERROR GBT_link_tree(TreeNode *tree, GBDATA *gb_main, bool show_status, int *zombies, int *duplicates)
Definition: adtree.cxx:953
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
static void update_marked_counter_label(GBDATA *gb_species_data, AW_awar *awar_counter_label)
static void nt_build_sai_string(GBDATA *gb_main, const char *topAreaSaiList, GBS_strstruct &topfile, GBS_strstruct &middlefile)
#define DEFAULT_CONFIGURATION
Definition: ad_config.h:30
TreeNode * rightson
Definition: TreeNode.h:171
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:231
GB_ERROR GB_delete(GBDATA *&source)
Definition: arbdb.cxx:1916
struct Unfixed_cb_parameter * UNFIXED
Definition: cb_base.h:15
POS_TREE1 * father
Definition: probe_tree.h:39
const char * read_char_pntr() const
Definition: AW_awar.cxx:168
static void nt_build_conf_marked(GBDATA *gb_main, GB_HASH *used, GBS_strstruct &file)
void to_array(StrArray &array, bool values)
Definition: AW_select.cxx:516
bool didMatch() const
Definition: RegExpr.hxx:37
static AW_root * SINGLETON
Definition: aw_root.hxx:102
bool exists() const
Definition: ad_config.h:51
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
#define TEST_EXPECT(cond)
Definition: test_unit.h:1328
char * GBT_read_string(GBDATA *gb_container, const char *fieldpath)
Definition: adtools.cxx:267
virtual const char * get_selectionComment_awarname() const =0
GBDATA * GB_create(GBDATA *father, const char *key, GB_TYPES type)
Definition: arbdb.cxx:1781
GBDATA * get_gb_main()
Definition: AW_select.cxx:592
GBDATA * gb_species_data
Definition: adname.cxx:33
long GB_number_of_subentries(GBDATA *gbd)
Definition: arbdb.cxx:2892
static void nt_rename_configuration(AW_window *aww, const SelectionAdmin *selection)
GBT_CONFIG_ITEM_TYPE type
Definition: ad_config.h:83
static void clear_comment_cb(AW_window *aww, const SelectionAdmin *selection)
Store_species * remove()
void help_text(const char *id)
Definition: AW_window.cxx:125
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1325
int get_index_of(const AW_scalar &searched_value)
Definition: AW_select.cxx:303
void touch()
Definition: AW_awar.cxx:207
const char * get_comment() const
Definition: ad_config.h:63
static void error(const char *msg)
Definition: mkptypes.cxx:96
GBDATA * GB_get_root(GBDATA *gbd)
Definition: arbdb.cxx:1740
#define AWAR_TREE_REFRESH
#define NO_CONFIG_SELECTED
const RegMatch * match(const std::string &versus, size_t offset=0) const
Definition: RegExpr.cxx:80
awt_reorder_mode
Definition: modules.hxx:22
void set_comment(const char *newComment)
Definition: ad_config.h:64
GBDATA * GBT_next_marked_species(GBDATA *gb_species)
Definition: aditem.cxx:116
CONSTEXPR_INLINE_Cxx14 void swap(unsigned char &c1, unsigned char &c2)
Definition: ad_io_inline.h:19
GB_ERROR save(GBDATA *gb_main, const char *name, bool warnIfSavingDefault) const
Definition: ad_config.h:67
size_t GBS_hash_elements(const GB_HASH *hs)
Definition: adhash.cxx:570
virtual void speciesSelection_renamed_cb(const char *old_name, const char *new_name) const =0
AW_DB_selection * awt_create_CONFIG_selection_list(GBDATA *gb_main, AW_window *aws, const char *varname)
Definition: sel_boxes.cxx:459
GBDATA * GBT_first_SAI_rel_SAI_data(GBDATA *gb_sai_data)
Definition: aditem.cxx:159
SelectionExtractType
static int nt_build_conf_string_rek(GB_HASH *used, TreeNode *tree, GBS_strstruct &memfile, Store_species **extra_marked_species, int use_species_aside, int *auto_mark, int marked_at_left, int *marked_at_right)
void safe_remove(int i)
Definition: arb_strarray.h:103
static SearchTree * tree[SEARCH_PATTERNS]
Definition: ED4_search.cxx:629
int GB_read_flag(GBDATA *gbd)
Definition: arbdb.cxx:2796
char * read_string() const
Definition: AW_awar.cxx:198
AW_window * create_species_selection_window(AW_root *root, const SelectionAdmin *selection)
GB_ERROR saveAsOver(GBDATA *gb_main, const char *name, const char *oldName, bool warnIfSavingDefault) const
Definition: ad_config.cxx:102
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
char * GBS_log_action_to(const char *comment, const char *action, bool stamp)
Definition: adstring.cxx:976
AW_awar * unmap()
Definition: AW_awar.cxx:596
Definition: arbdb.h:86
GBDATA * GBT_find_configuration(GBDATA *gb_main, const char *name)
Definition: ad_config.cxx:58
void call(void(*aPizza)(TreeNode *)) const
static AW_window_menu_modes_opengl * awm
SelectionCreation
long GBT_count_marked_species(GBDATA *gb_main)
Definition: aditem.cxx:372
static void reorder_configs_cb(AW_window *aww, awt_reorder_mode mode, AW_DB_selection *sel)
#define TEST_EXPECT_ZERO(cond)
Definition: test_unit.h:1085
void extract_species_selection(GBDATA *gb_main, const char *selectionName, SelectionExtractType ext_type)
const std::string * has_failed() const
Definition: RegExpr.hxx:78
char * GBT_join_strings(const CharPtrArray &strings, char separator)
GBDATA * GBT_next_SAI(GBDATA *gb_sai)
Definition: aditem.cxx:166
void ncat(const char *from, size_t count)
Definition: arb_strbuf.h:189
bool is_leaf() const
Definition: TreeNode.h:211
#define TEST_EXPECT_NULL(n)
Definition: test_unit.h:1322
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:35
void GB_write_flag(GBDATA *gbd, long flag)
Definition: arbdb.cxx:2773
GB_ERROR GBT_write_string(GBDATA *gb_container, const char *fieldpath, const char *content)
Definition: adtools.cxx:451
const GBT_config_item & nextItem(GB_ERROR &error)
Definition: ad_config.cxx:140
virtual const char * get_toparea_SAIs() const =0
void move_selection(int offset)
Definition: AW_select.cxx:415
static TreeNode * left_neighbour_leaf(TreeNode *node)
const char * get_awar_name() const
Definition: aw_select.hxx:82
char * name
Definition: TreeNode.h:174
int GB_read_byte(GBDATA *gbd)
Definition: arbdb.cxx:734
AW_awar * map(const char *awarn)
Definition: AW_awar.cxx:521
char * GB_read_string(GBDATA *gbd)
Definition: arbdb.cxx:909
GB_ERROR GB_write_byte(GBDATA *gbd, int i)
Definition: arbdb.cxx:1238
static void nt_store_configuration(AW_window *, const SelectionAdmin *selection)
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1118
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
int GBS_HCF_sortedByKey(const char *k0, long dummy_1x, const char *k1, long dummy_2x)
Definition: adhash.cxx:653
AW_root * get_root()
Definition: aw_window.hxx:362
static int line
Definition: arb_a2ps.c:296
static TreeNode * rightmost_leaf(TreeNode *node)
#define NULp
Definition: cxxforward.h:116
GBDATA * GBT_find_species(GBDATA *gb_main, const char *name)
Definition: aditem.cxx:139
void create_species_selection_button(AW_window *awm, WindowCallback wcb, const char *macro_id, const char *awarname_buttontext, GBDATA *gb_main)
GB_ERROR write_string(const char *aw_string)
void GBT_split_string(ConstStrArray &dest, const char *namelist, const char *separator, SplitMode mode)
Definition: arb_strarray.h:223
GB_ERROR GB_ensure_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:445
const char * get_data() const
Definition: arb_strbuf.h:120
GBDATA * GBT_find_SAI_rel_SAI_data(GBDATA *gb_sai_data, const char *name)
Definition: aditem.cxx:171
int GB_get_transaction_level(GBDATA *gbd)
Definition: arbdb.cxx:2590
static void nt_extract_configuration(UNFIXED, const SelectionAdmin *selection, SelectionExtractType ext_type)
virtual const char * get_macro_suffix() const =0
long GBT_get_species_count(GBDATA *gb_main)
Definition: aditem.cxx:207
GB_ERROR create_species_selection(const SelectionAdmin &selection, const char *conf_name, int use_species_aside, SelectionCreation creation)
static void mark_species(TreeNode *node, Store_species **extra_marked_species)
GB_transaction ta(gb_var)
void callback(const WindowCallback &cb)
Definition: AW_window.cxx:142
static void config_comment_changed_cb(AW_root *root, const SelectionAdmin *selection)
void destroy(TreeNode *that)
Definition: TreeNode.h:600
GBDATA * gb_node
Definition: TreeNode.h:173
GBDATA * gb_main
Definition: adname.cxx:32
virtual const char * get_window_title() const =0
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:622
GBDATA * GBT_get_SAI_data(GBDATA *gb_main)
Definition: aditem.cxx:154
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
static void selected_config_changed_cb(AW_root *root, const SelectionAdmin *selection)
char * aw_input(const char *title, const char *prompt, const char *default_input)
Definition: AW_modal.cxx:252
void GBT_splitNdestroy_string(ConstStrArray &names, char *&namelist, const char *separator, SplitMode mode)
virtual GBDATA * get_gb_main() const =0
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1294
static GB_ERROR swap_configs(GBDATA *gb_main, StrArray &config, int i1, int i2)
static void nt_build_sai_string_by_hash(const char *key, long, void *cd_sai_builder)
bool is_normal_group() const
Definition: TreeNode.h:470
long GBS_read_hash(const GB_HASH *hs, const char *key)
Definition: adhash.cxx:392
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
size_t get_position() const
Definition: arb_strbuf.h:112
AW_selection_list * get_sellist()
Definition: aw_select.hxx:196
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:655
void set_definition(int area, char *new_def)
Definition: ad_config.h:57
const char * last_group_name
GBS_strstruct & sai_middle
GB_HASH * GBS_create_hash(long estimated_elements, GB_CASE case_sens)
Definition: adhash.cxx:253
void put(char c)
Definition: arb_strbuf.h:174
virtual class TreeNode * get_tree_root() const =0
void create_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, const char *color=NULp)
Definition: AW_button.cxx:448
#define UNCOVERED()
Definition: arb_assert.h:380
GBDATA * GBT_get_species_data(GBDATA *gb_main)
Definition: aditem.cxx:105
GB_write_int const char s
Definition: AW_awar.cxx:154