ARB
DI_clusters.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : DI_clusters.cxx //
4 // Purpose : Detect clusters of homologous sequences in tree //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in October 2009 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // =============================================================== //
11 
12 #include "di_clusters.hxx"
13 #include "di_clustertree.hxx"
14 #include "di_foundclusters.hxx"
15 #include "di_awars.hxx"
16 
17 #include <AP_seq_protein.hxx>
18 #include <AP_seq_dna.hxx>
19 
20 #include <awt_sel_boxes.hxx>
21 
22 #include <aw_awars.hxx>
23 #include <aw_msg.hxx>
24 #include <arb_progress.h>
25 #include <aw_root.hxx>
26 
27 #include <list>
28 
29 using namespace std;
30 
31 #define di_assert(cond) arb_assert(cond)
32 
33 // --------------
34 // awars
35 
36 #define AWAR_CLUSTER_PREFIX AWAR_DIST_PREFIX "cluster/"
37 #define AWAR_CLUSTER_PREFIX_TEMP "/tmp/" AWAR_DIST_PREFIX
38 
39 #define AWAR_CLUSTER_MAXDIST AWAR_CLUSTER_PREFIX "maxdist"
40 #define AWAR_CLUSTER_MINSIZE AWAR_CLUSTER_PREFIX "minsize"
41 #define AWAR_CLUSTER_AUTOMARK AWAR_CLUSTER_PREFIX "automark"
42 #define AWAR_CLUSTER_MARKREP AWAR_CLUSTER_PREFIX "markrep"
43 #define AWAR_CLUSTER_SELECTREP AWAR_CLUSTER_PREFIX "selrep"
44 #define AWAR_CLUSTER_ORDER AWAR_CLUSTER_PREFIX "order"
45 
46 #define AWAR_CLUSTER_GRP_PREFIX AWAR_CLUSTER_PREFIX "group/"
47 #define AWAR_CLUSTER_GRP_PREFIX_TMP "/tmp/" AWAR_CLUSTER_GRP_PREFIX
48 
49 #define AWAR_CLUSTER_GROUP_WHAT AWAR_CLUSTER_GRP_PREFIX "all"
50 #define AWAR_CLUSTER_GROUP_EXISTING AWAR_CLUSTER_GRP_PREFIX "existing"
51 #define AWAR_CLUSTER_GROUP_NOTFOUND AWAR_CLUSTER_GRP_PREFIX "notfound"
52 #define AWAR_CLUSTER_GROUP_IDENTITY AWAR_CLUSTER_GRP_PREFIX "identity"
53 #define AWAR_CLUSTER_GROUP_PREFIX AWAR_CLUSTER_GRP_PREFIX "prefix"
54 #define AWAR_CLUSTER_GROUP_PREFIX_MATCH AWAR_CLUSTER_GRP_PREFIX "prefix_match"
55 #define AWAR_CLUSTER_GROUP_SUFFIX AWAR_CLUSTER_GRP_PREFIX "suffix"
56 #define AWAR_CLUSTER_GROUP_EXAMPLE AWAR_CLUSTER_GRP_PREFIX_TMP "example"
57 
58 #define AWAR_CLUSTER_SELECTED AWAR_CLUSTER_PREFIX_TEMP "selected" // ID of currently selected cluster (or zero)
59 #define AWAR_CLUSTER_RESTORE_LABEL AWAR_CLUSTER_PREFIX_TEMP "rlabel" // label of restore button
60 
61 enum Group_What {
64 };
65 
69 };
70 
75 };
76 
82 };
83 
84 // ----------------------------------------
85 
87 
89 
90 // ------------------------
91 
93  di_assert(global_data);
94  global_data->free();
95  // do not delete 'global_data' itself, it will be reused when window is opened again
96 }
97 
98 // ------------------------
99 // Update contents
100 
101 static void update_cluster_sellist() {
102  global_data->update_cluster_selection_list();
103  // @@@ update result info line
104 }
105 static void update_restore_label(AW_window *aww) {
106  AW_root *aw_root = aww->get_root();
107  AW_awar *awar = aw_root->awar(AWAR_CLUSTER_RESTORE_LABEL);
108  unsigned size = global_data->count(STORED_CLUSTERS);
109  const char *label = size ? GBS_global_string("Stored: %u", size) : "None stored";
110 
111  awar->write_string(label);
112 }
113 static void update_all(AW_window *aww) {
116 }
117 
118 static void save_results_recursive(ClusterTree *subtree) {
119  if (subtree->get_state() == CS_IS_CLUSTER) {
120  global_data->add(new Cluster(subtree), SHOWN_CLUSTERS);
121  }
122  if (!subtree->is_leaf()) {
123  save_results_recursive(subtree->get_leftson());
124  save_results_recursive(subtree->get_rightson());
125  }
126 }
127 static void save_results(ClusterTreeRoot *tree) {
128  global_data->clear(SHOWN_CLUSTERS);
129  save_results_recursive(tree->get_root_node());
131 }
132 
133 static void calculate_clusters(AW_window *aww) {
134  GBDATA *gb_main = global_data->get_gb_main();
135  GB_ERROR error = NULp;
136 
137  arb_progress progress("Detecting clusters");
138 
139  // calculate ClusterTree
140  ClusterTreeRoot *tree = NULp;
141  {
142  GB_transaction ta(gb_main);
143  AW_root *aw_root = aww->get_root();
144 
145  {
146  char *use = aw_root->awar(AWAR_DIST_ALIGNMENT)->read_string();
147  AliView *aliview = global_data->weighted_filter.create_aliview(use, error);
148 
149  if (aliview) {
150  AP_sequence *seq = GBT_is_alignment_protein(gb_main, use)
151  ? (AP_sequence*)new AP_sequence_protein(aliview)
152  : new AP_sequence_parsimony(aliview);
153 
154  float maxDistance = aw_root->awar(AWAR_CLUSTER_MAXDIST)->read_float();
155  unsigned minClusterSize = aw_root->awar(AWAR_CLUSTER_MINSIZE)->read_int();
156 
157  tree = new ClusterTreeRoot(aliview, seq, maxDistance/100, minClusterSize);
158 
159  delete seq;
160  }
161  free(use);
162  }
163 
164  if (!error) {
165  progress.subtitle("Loading tree");
166  {
167  char *tree_name = aw_root->awar(AWAR_DIST_TREE_CURR_NAME)->read_string();
168  error = tree->loadFromDB(tree_name);
169  free(tree_name);
170  }
171 
172  if (!error) error = tree->linkToDB(NULp, NULp);
173  }
174  }
175 
176  if (!error) {
177  error = tree->find_clusters();
178  if (!error) save_results(tree);
179  }
180 
181  delete tree;
182 
183  if (error) aw_message(error);
184 }
185 
186 DECLARE_CBTYPE_FVV_AND_BUILDERS(ClusterCallback, void, ClusterPtr); // generates makeClusterCallback
187 
188 inline bool is_cluster(ID id) {
189  // 0 is 'no cluster' and -1 is used for list header
190  return id>0;
191 }
192 
193 static int with_affected_clusters_do(AW_root *aw_root, AffectedClusters affected, bool warn_if_none_affected, ClusterCallback cb) {
194  // returns number of affected clusters
195  int affCount = 0;
196  if (affected == SEL_CLUSTER) {
197  AW_awar *awar = aw_root->awar(AWAR_CLUSTER_SELECTED);
198  ID selID = awar->read_int();
199 
200  if (is_cluster(selID)) {
201  ClusterPtr selCluster = global_data->clusterWithID(selID);
202  cl_assert(!selCluster.isNull());
203  cb(selCluster);
204  affCount++;
205  }
206  else if (warn_if_none_affected) {
207  aw_message("No cluster is selected");
208  }
209  }
210  else {
211  unsigned shown = global_data->count(SHOWN_CLUSTERS);
212  if (shown) {
213  ClusterIDs clusters(global_data->get_clusterIDs(SHOWN_CLUSTERS)); // intended copy!
214  ClusterIDsIter cli_end = clusters.end();
215  for (ClusterIDsIter cli = clusters.begin(); cli != cli_end; ++cli) {
216  ClusterPtr cluster = global_data->clusterWithID(*cli);
217  cb(cluster);
218  affCount++;
219  }
220  }
221  else if (warn_if_none_affected) {
222  aw_message("There are no clusters in the list");
223  }
224  }
225  return affCount;
226 }
227 
228 // -------------
229 // mark
230 
232  DBItemSetIter sp_end = members.end();
233  for (DBItemSetIter sp = members.begin(); sp != sp_end; ++sp) {
234  bool is_rep = *sp == representative;
235  bool mark = false;
236 
237  switch (mmode) {
238  case CMM_ALL: mark = true; break;
239  case CMM_ONLY_REP: mark = is_rep; break;
240  case CMM_ALL_BUT_REP: mark = !is_rep; break;
241  }
242 
243  if (mark) GB_write_flag(*sp, 1);
244  }
245 }
246 
247 static void mark_cluster(ClusterPtr cluster, ClusterMarkMode markRep) {
248  cluster->mark_all_members(markRep);
249 }
250 static void select_representative(ClusterPtr cluster) {
251  GBDATA *gb_species = cluster->get_representative();
252  GB_transaction ta(gb_species);
253  global_data->get_aw_root()->awar(AWAR_SPECIES_NAME)->write_string(null2empty(GBT_get_name(gb_species)));
254 }
255 
256 static void mark_clusters(AW_window *, AffectedClusters affected, bool warn_if_none_affected) {
257  AW_root *aw_root = global_data->get_aw_root();
258  GBDATA *gb_main = global_data->get_gb_main();
259 
260  GB_transaction ta(gb_main);
262 
263  GBT_mark_all(gb_main, 0); // unmark all
264  with_affected_clusters_do(aw_root, affected, warn_if_none_affected, makeClusterCallback(mark_cluster, markRep));
265  aw_root->awar(AWAR_TREE_REFRESH)->touch();
266 }
267 
268 static void select_cluster_cb(AW_root *aw_root) {
269  GB_transaction ta(global_data->get_gb_main());
270 
271  bool auto_mark = aw_root->awar(AWAR_CLUSTER_AUTOMARK)->read_int();
272  if (auto_mark) mark_clusters(NULp, SEL_CLUSTER, false);
273 
274  bool selRep = aw_root->awar(AWAR_CLUSTER_SELECTREP)->read_int();
275  if (selRep) {
276  int selected = with_affected_clusters_do(aw_root, SEL_CLUSTER, false, makeClusterCallback(select_representative));
277  if (!selected) aw_root->awar(AWAR_SPECIES_NAME)->write_string(""); // deselect species
278  }
279 }
280 
281 static void select_cluster(ID id) {
282  global_data->get_aw_root()->awar(AWAR_CLUSTER_SELECTED)->write_int(id);
283 }
284 
285 
286 // -------------------
287 // Sort order
288 
289 
290 static void sort_order_changed_cb(AW_root *aw_root) {
292  global_data->changeSortOrder(order);
294 }
295 
296 // --------------
297 // group
298 
299 class GroupTree;
300 typedef map<string, GroupTree*> Species2Tip;
301 
302 struct GroupTreeRoot FINAL_TYPE : public ARB_seqtree_root {
303  GroupTreeRoot(AliView *aliView, AP_sequence *seqTempl, bool add_delete_callbacks);
304  ~GroupTreeRoot() OVERRIDE { predelete(); }
305  inline TreeNode *makeNode() const OVERRIDE;
306  inline void destroyNode(TreeNode *node) const OVERRIDE;
307 };
308 
309 class GroupTree FINAL_TYPE : public ARB_countedTree {
310  unsigned leaf_count; // total number of leafs in subtree
311  unsigned tagged_count; // tagged leafs
312 
313  void update_tag_counters();
314  unsigned get_leaf_count() const OVERRIDE { return leaf_count; }
315 protected:
316  ~GroupTree() OVERRIDE {}
317  friend class GroupTreeRoot;
318 public:
319 
320  explicit GroupTree(GroupTreeRoot *root)
321  : ARB_countedTree(root),
322  leaf_count(0),
323  tagged_count(0)
324  {}
325 
326  // ARB_countedTree interface
327  void init_tree() OVERRIDE { update_leaf_counters(); }
328  // ARB_countedTree interface end
329 
331 
332  void map_species2tip(Species2Tip& mapping);
333 
334  unsigned update_leaf_counters();
335 
336  void tag_leaf() {
337  di_assert(is_leaf());
338  tagged_count = 1;
339  get_father()->update_tag_counters();
340  }
341  unsigned get_tagged_count() const { return tagged_count; }
342  void clear_tags();
343 
344  float tagged_rate() const { return float(get_tagged_count())/get_leaf_count(); }
345 };
346 
347 GroupTreeRoot::GroupTreeRoot(AliView *aliView, AP_sequence *seqTempl, bool add_delete_callbacks)
348  : ARB_seqtree_root(aliView, seqTempl, add_delete_callbacks)
349 {}
350 inline TreeNode *GroupTreeRoot::makeNode() const { return new GroupTree(const_cast<GroupTreeRoot*>(this)); }
351 inline void GroupTreeRoot::destroyNode(TreeNode *node) const { delete DOWNCAST(GroupTree*,node); }
352 
353 
354 unsigned GroupTree::update_leaf_counters() {
355  if (is_leaf()) leaf_count = 1;
356  else leaf_count = get_leftson()->update_leaf_counters() + get_rightson()->update_leaf_counters();
357  return leaf_count;
358 }
359 
360 void GroupTree::clear_tags() {
361  if (!is_leaf() && tagged_count) {
362  get_leftson()->clear_tags();
363  get_rightson()->clear_tags();
364  }
365  tagged_count = 0;
366 }
367 
368 void GroupTree::map_species2tip(Species2Tip& mapping) {
369  if (is_leaf()) {
370  if (name) mapping[name] = this;
371  }
372  else {
373  get_leftson()->map_species2tip(mapping);
374  get_rightson()->map_species2tip(mapping);
375  }
376 }
377 
378 void GroupTree::update_tag_counters() {
379  di_assert(!is_leaf());
380  GroupTree *node = this;
381  while (node) {
382  node->tagged_count = node->get_leftson()->get_tagged_count() + node->get_rightson()->get_tagged_count();
383  node = node->get_father();
384  }
385 }
386 
387 struct GroupChanges {
388  unsigned created;
389  unsigned skipped;
390  unsigned overwritten;
391  unsigned deleted;
392  unsigned restored;
393 
394  void clear() { created = skipped = overwritten = deleted = restored = 0; }
395  bool exist() const { return created||overwritten||deleted||restored; }
396 
397  void show_message() {
398  string msg;
399 
400  if (created) msg += GBS_global_string("%u created ", created);
401  if (overwritten) msg += GBS_global_string("%u overwritten ", overwritten);
402  if (skipped) msg += GBS_global_string("%u skipped ", skipped);
403  if (deleted) msg += GBS_global_string("%u deleted ", deleted);
404  if (restored) msg += GBS_global_string("%u restored ", restored);
405 
406  if (!msg.empty()) {
407  msg = string("Group changes: ")+msg;
408  aw_message(msg.c_str());
409  }
410  }
411 
413 };
414 
415 
416 // ---------------------
417 // GroupBuilder
418 
419 class GroupBuilder : virtual Noncopyable {
420  GBDATA *gb_main;
421  string tree_name;
422  GroupTreeRoot *tree_root;
423  Group_Action action; // create or delete ?
424  Species2Tip species2tip; // map speciesName -> leaf
425  ARB_ERROR error;
426  ClusterPtr bad_cluster; // error occurred here (is set)
427  Group_Existing existing;
428  unsigned existing_count; // counts existing groups
429  Group_NotFound notfound;
430  float matchRatio; // needed identity of subtree and cluster
431  float maxDist; // max. Distance used for calculation
432  string cluster_prefix; // prefix for cluster name
433  string cluster_suffix_def; // suffix-definition for cluster name
434  GroupChanges changes; // count tree modifications
435  bool del_match_prefixes; // only delete groups, where prefix matches
436 
437  GroupTree *find_group_position(GroupTree *subtree, unsigned cluster_size);
438  float get_max_distance() const { return maxDist; }
439  void load_tree();
440 
441  DEFINE_DOWNCAST_ACCESSORS(GroupTree, get_root_node, tree_root->get_root_node());
442 
443  bool shall_delete_group(const char *name) const {
444  return !del_match_prefixes || matches_current_prefix(name);
445  }
446 
447 public:
448  GroupBuilder(GBDATA *gb_main_, Group_Action action_)
449  : gb_main(gb_main_),
450  tree_root(NULp),
451  action(action_),
452  error(NULp),
453  existing_count(0)
454  {
455  AW_root *awr = global_data->get_aw_root();
456 
457  tree_name = awr->awar(AWAR_DIST_TREE_CURR_NAME)->read_char_pntr();
460  del_match_prefixes = awr->awar(AWAR_CLUSTER_GROUP_PREFIX_MATCH)->read_int();
461  matchRatio = awr->awar(AWAR_CLUSTER_GROUP_IDENTITY)->read_int()/100.0;
462  maxDist = awr->awar(AWAR_CLUSTER_MAXDIST)->read_float();
463  cluster_prefix = awr->awar(AWAR_CLUSTER_GROUP_PREFIX)->read_char_pntr();
464  cluster_suffix_def = awr->awar(AWAR_CLUSTER_GROUP_SUFFIX)->read_char_pntr();
465  }
466  ~GroupBuilder() { delete tree_root; }
467 
468  ARB_ERROR get_error() const { return error; }
469  ClusterPtr get_bad_cluster() const { return bad_cluster; }
470 
472 
473  GroupTree *find_best_matching_subtree(ClusterPtr cluster);
474  void update_group(ClusterPtr cluster); // create or delete group for cluster
475  string generate_group_name(ClusterPtr cluster, const GroupTree *group_node);
476 
477  bool matches_current_prefix(const char *groupname) const {
478  return strstr(groupname, cluster_prefix.c_str()) == groupname;
479  }
480 };
481 
482 void GroupBuilder::load_tree() {
483  di_assert(!tree_root);
484 
485  tree_root = new GroupTreeRoot(new AliView(gb_main), NULp, false);
486  error = tree_root->loadFromDB(tree_name.c_str());
487 
488  if (error) {
489  delete tree_root;
490  tree_root = NULp;
491  }
492  else {
493  changes.clear();
494 
495  GroupTree *tree = get_root_node();
496  tree->update_leaf_counters();
497  tree->map_species2tip(species2tip);
498  }
499 }
501  di_assert(!error);
502  if (changes.exist()) {
503  di_assert(tree_root);
504  error = tree_root->saveToDB();
505 
506  AW_root *awr = global_data->get_aw_root();
507  awr->awar(AWAR_TREE_REFRESH)->touch();
508 
509  if (!error) {
510  changes.show_message();
511  changes.clear();
512  }
513  }
514  return error;
515 }
516 
517 GroupTree *GroupBuilder::find_group_position(GroupTree *subtree, unsigned cluster_size) {
518  // searches for best group in subtree matching the cluster
519 
520  GroupTree *groupPos = NULp;
521  if (subtree->get_tagged_count() == cluster_size) {
522  groupPos = find_group_position(subtree->get_leftson(), cluster_size);
523  if (!groupPos) groupPos = find_group_position(subtree->get_rightson(), cluster_size);
524 
525  if (!groupPos) { // consider 'subtree'
526  if (subtree->tagged_rate() >= matchRatio) {
527  groupPos = subtree;
528  }
529  }
530  }
531  return groupPos;
532 }
533 
535  const GroupBuilder& builder;
536  bool selects(const ARB_seqtree& tree) const OVERRIDE {
537  const char *groupname = tree.get_group_name();
538  bool hasClusterPrefix = groupname && builder.matches_current_prefix(groupname);
539  return !hasClusterPrefix;
540  }
541 public:
542  HasntCurrentClusterPrefix(const GroupBuilder& builder_) : builder(builder_) {}
543 };
544 
545 string concatenate_name_parts(const list<string>& namepart) {
546  string concat;
547  for (list<string>::const_iterator p = namepart.begin(); p != namepart.end(); ++p) {
548  if (!p->empty()) concat += '_'+*p;
549  }
550  return concat.erase(0, 1);
551 }
552 
554  bool selects(const ARB_seqtree& tree) const OVERRIDE { return tree.is_root_node(); }
555 };
556 
557 string GroupBuilder::generate_group_name(ClusterPtr cluster, const GroupTree *group_node) {
558  list<string> namepart;
559  namepart.push_back(cluster_prefix);
560 
561  string orgname_suffix;
562  if (existing == EXISTING_GROUP_APPEND_ORG) {
563  char *old_name = group_node->name;
564  if (old_name) {
565  char *original = originalGroupName(old_name);
566  if (!original && !matches_current_prefix(old_name)) {
567  original = ARB_strdup(old_name); // use existing name as original name
568  }
569  if (original) {
570  orgname_suffix = string(" {was:")+original+"}";
571  free(original);
572  }
573  }
574  }
575 
576  string text;
577  for (int i = 0; cluster_suffix_def[i]; ++i) {
578  if (cluster_suffix_def[i] == '%') {
579  ++i;
580  if (cluster_suffix_def[i] == '%') {
581  text += '%';
582  }
583  else {
584  string expanded;
585  switch(cluster_suffix_def[i]) {
586  case 'p': expanded = cluster->get_upgroup_info(group_node, HasntCurrentClusterPrefix(*this)); break;
587  case 'P': expanded = cluster->get_upgroup_info(group_node, UseAnyTree()); break;
588  case 't': expanded = cluster->get_upgroup_info(group_node, UseTreeRoot()); break;
589  case 'd': expanded = GBS_global_string("~%.3f", cluster->get_mean_distance()); break;
590  case 'D': expanded = GBS_global_string("<=%.1f%%", get_max_distance()); break;
591  case 'e': expanded = null2empty(group_node->name); break;
592  case 'o': {
593  int matchRate = int(group_node->tagged_rate()*100+0.5);
594  if (matchRate<100) expanded = GBS_global_string("%i%%_of", matchRate);
595  break;
596  }
597  default:
598  text += '%';
599  text += cluster_suffix_def[i];
600  break;
601  }
602 
603  if (!expanded.empty()) {
604  namepart.push_back(text);
605  text = "";
606  namepart.push_back(expanded);
607  }
608  }
609  }
610  else {
611  text += cluster_suffix_def[i];
612  }
613  }
614  namepart.push_back(text);
615 
616  return concatenate_name_parts(namepart)+orgname_suffix;
617 }
618 
620  GroupTree *group_node = NULp;
621  if (!error) {
622  if (!tree_root) load_tree();
623  if (!error) {
624  const DBItemSet& members = cluster->get_members();
625 
626  // mark cluster members in tree
627  {
628  GB_transaction ta(gb_main);
629  DBItemSetIter sp_end = members.end();
630  for (DBItemSetIter sp = members.begin(); sp != sp_end && !error; ++sp) {
631  const char *name = GBT_get_name(*sp);
632  di_assert(name);
633  if (name) {
634  Species2Tip::const_iterator found = species2tip.find(name);
635  if (found == species2tip.end()) {
636  error = GBS_global_string("Species '%s' is not in '%s'", name, tree_name.c_str());
637  }
638  else {
639  GroupTree *leaf = found->second;
640  leaf->tag_leaf();
641  }
642  }
643  }
644  }
645 
646  if (!error) {
647  // top-down search for best matching node
648  group_node = find_group_position(get_root_node(), cluster->get_member_count());
649  }
650  }
651  }
652  return group_node;
653 }
654 
656  if (!error) {
657  GroupTree *group_node = find_best_matching_subtree(cluster);
658  if (!error) {
659  if (!group_node) { // no matching subtree found
660  switch (notfound) {
661  case NOTFOUND_WARN:
662  case NOTFOUND_ABORT: {
663  const char *msg = GBS_global_string("Could not find matching subtree for cluster '%s'", cluster->get_list_display(NULp));
664  if (notfound == NOTFOUND_ABORT) error = msg;
665  else aw_message(msg);
666  break;
667  }
668  case NOTFOUND_IGNORE: break; // silently ignore
669  }
670  }
671  else { // found subtree for group
672  switch (action) {
673  case GROUP_CREATE: {
674  char *old_name = group_node->name;
675 
676  if (old_name && existing == EXISTING_GROUP_ABORT) {
677  error = GBS_global_string("Existing group '%s' is in the way", old_name);
678  }
679  else {
680  if (old_name && existing == EXISTING_GROUP_SKIP) {
681  changes.skipped++;
682  }
683  else {
684  string new_name = generate_group_name(cluster, group_node);
685 
686  if (old_name) changes.overwritten++; else changes.created++;
687 
688  free(old_name);
689  group_node->name = ARB_strdup(new_name.c_str());
690 
691  // @@@ DRY that.. it's spread everywhere through libs :(
692  if (!group_node->gb_node) {
693  GBDATA *gb_tree = group_node->get_tree_root()->get_gb_tree();
694  GB_transaction ta(gb_tree);
695  GBDATA *gb_node = GB_create_container(gb_tree, "node");
696  if (!gb_node) {
697  error = GB_await_error();
698  }
699  else {
700  error = GBT_write_int(gb_node, "id", 0);
701  }
702 
703  if (!error) {
704  group_node->gb_node = gb_node;
705  }
706  }
707  if (group_node->gb_node && !error) {
708  GB_transaction ta(group_node->gb_node);
709  error = GBT_write_name_to_groupData(group_node->gb_node, true, group_node->name, true);
710  // @@@ if INT-field "keeled" exists -> set to 0
711  }
712 
713  cluster->update_description(group_node); // change list display
714  }
715  }
716  break;
717  }
718  case GROUP_DELETE: {
719  if (group_node->name && shall_delete_group(group_node->name)) {
720  char *original = originalGroupName(group_node->name);
721 
722  if (original) {
723  freeset(group_node->name, original); // restore original name
724  if (group_node->gb_node) {
725  error = GBT_write_name_to_groupData(group_node->gb_node, true, group_node->name, true);
726  // @@@ original keeled state is not restored here
727  }
728  changes.restored++;
729  }
730  else {
731  freenull(group_node->name);
732  group_node->gb_node = NULp; // forget ref to group data (@@@ need to delete group data from DB?)
733  changes.deleted++;
734  }
735 
736  cluster->update_description(group_node); // change list display
737  }
738  break;
739  }
740  }
741  }
742  }
743 
744  if (error) bad_cluster = cluster;
745  get_root_node()->clear_tags();
746  }
747 }
748 
749 static void update_example(AW_root *aw_root) {
750  ID selID = aw_root->awar(AWAR_CLUSTER_SELECTED)->read_int();
751  string value;
752 
753  if (is_cluster(selID)) {
754  ClusterPtr selCluster = global_data->clusterWithID(selID);
755  cl_assert(!selCluster.isNull());
756 
757  GroupBuilder builder(global_data->get_gb_main(), GROUP_CREATE);
758  GroupTree *group_node = builder.find_best_matching_subtree(selCluster);
759 
760  GB_ERROR error = builder.get_error().deliver();
761 
762  if (error) value = GBS_global_string("<error: %s>", error);
763  else if (group_node) value = builder.generate_group_name(selCluster, group_node);
764  else value = "<no matching subtree found>";
765  }
766  else value = "<no cluster selected>";
767  aw_root->awar(AWAR_CLUSTER_GROUP_EXAMPLE)->write_string(value.c_str());
768 }
769 
770 static void update_cluster_group(ClusterPtr cluster, GroupBuilder *groupBuilder) {
771  if (!groupBuilder->get_error()) {
772  groupBuilder->update_group(cluster);
773  }
774 }
775 
776 static void accept_proposed_names(ClusterPtr cluster, bool accept) {
777  cluster->accept_proposed(accept);
778 }
779 
780 static void group_clusters(AW_window *, Group_Action action) {
781  AW_root *aw_root = global_data->get_aw_root();
783  AffectedClusters affected = what == GROUP_LISTED ? ALL_CLUSTERS : SEL_CLUSTER;
784 
785  GroupBuilder groupBuilder(global_data->get_gb_main(), action);
786 
787  GB_transaction ta(global_data->get_gb_main());
788  with_affected_clusters_do(aw_root, affected, true, makeClusterCallback(update_cluster_group, &groupBuilder));
789 
790  ARB_ERROR error = groupBuilder.get_error();
791  if (error) {
792  ClusterPtr bad = groupBuilder.get_bad_cluster();
793  if (!bad.isNull()) {
794  select_cluster(bad->get_ID());
795  aw_message("Problematic cluster has been highlighted");
796  }
797  }
798  else {
799  error = groupBuilder.save_modified_tree();
800  }
801 
802  error = ta.close(error);
803 
804  bool accept = !error;
805  aw_message_if(error);
806  // careful! the following code will invalidate error, so don't use below
807 
808  with_affected_clusters_do(aw_root, affected, false, makeClusterCallback(accept_proposed_names, accept)); // just affects display
809  global_data->update_cluster_selection_list();
810 }
811 
812 static void popup_group_clusters_window(AW_window *aw_clusterList) {
813  static AW_window_simple *aws = NULp;
814 
815  if (!aws) {
816  AW_root *aw_root = aw_clusterList->get_root();
817 
818  aws = new AW_window_simple;
819  aws->init(aw_root, "cluster_groups", "Cluster groups");
820 
821  aws->auto_space(10, 10);
822 
823  aws->callback(AW_POPDOWN);
824  aws->create_button("CLOSE", "CLOSE", "C");
825 
826  aws->callback(makeHelpCallback("cluster_group.hlp"));
827  aws->create_button("HELP", "HELP");
828 
829  aws->at_newline();
830 
831  aws->label("For");
832  aws->create_option_menu(AWAR_CLUSTER_GROUP_WHAT, true);
833  aws->insert_option ("selected cluster", "s", GROUP_SELECTED);
834  aws->insert_default_option("listed clusters", "l", GROUP_LISTED);
835  aws->update_option_menu();
836 
837  aws->at_newline();
838 
839  aws->label("with a min. cluster/subtree identity (%) of");
840  aws->create_input_field(AWAR_CLUSTER_GROUP_IDENTITY, 4);
841 
842  aws->at_newline();
843 
844  aws->label("-> if no matching subtree found");
845  aws->create_option_menu(AWAR_CLUSTER_GROUP_NOTFOUND, true);
846  aws->insert_default_option("abort", "a", NOTFOUND_ABORT);
847  aws->insert_option ("warn", "w", NOTFOUND_WARN);
848  aws->insert_option ("ignore", "i", NOTFOUND_IGNORE);
849  aws->update_option_menu();
850 
851  aws->at_newline();
852 
853  aws->callback(makeWindowCallback(group_clusters, GROUP_CREATE));
854  aws->create_autosize_button("CREATE_GROUPS", "create groups!");
855 
856  aws->label("If group exists");
857  aws->create_option_menu(AWAR_CLUSTER_GROUP_EXISTING, true);
858  aws->insert_default_option("abort", "a", EXISTING_GROUP_ABORT);
859  aws->insert_option ("skip", "s", EXISTING_GROUP_SKIP);
860  aws->insert_option ("overwrite (caution!)", "o", EXISTING_GROUP_OVERWRITE);
861  aws->insert_option ("append original", "p", EXISTING_GROUP_APPEND_ORG);
862  aws->update_option_menu();
863 
864  aws->at_newline();
865 
866  aws->callback(makeWindowCallback(group_clusters, GROUP_DELETE));
867  aws->create_autosize_button("DELETE_GROUPS", "delete groups!");
868 
869  aws->create_text_toggle(AWAR_CLUSTER_GROUP_PREFIX_MATCH, "(all)", "(where prefix matches)", 30);
870 
871  aws->at_newline(); aws->label("Name prefix:"); aws->create_input_field(AWAR_CLUSTER_GROUP_PREFIX, 20);
872  aws->at_newline(); aws->label("Name suffix:"); aws->create_input_field(AWAR_CLUSTER_GROUP_SUFFIX, 20);
873 
874  aws->at_newline();
875  aws->button_length(60);
876  aws->label("=>");
877  aws->create_button(NULp, AWAR_CLUSTER_GROUP_EXAMPLE);
878 
879  aws->window_fit();
880  }
881 
882  aws->activate();
883 }
884 
885 // ---------------
886 // delete
887 
888 static void delete_selected_cluster(ClusterPtr cluster) {
889  int pos = global_data->get_pos(cluster, SHOWN_CLUSTERS);
890  int nextId = global_data->idAtPos(pos+1, SHOWN_CLUSTERS);
891  select_cluster(nextId);
892  global_data->remove(cluster, SHOWN_CLUSTERS);
893 }
894 static void delete_clusters(AW_window *aww, AffectedClusters affected) {
895  switch (affected) {
896  case SEL_CLUSTER:
897  with_affected_clusters_do(aww->get_root(), affected, true, makeClusterCallback(delete_selected_cluster));
898  break;
899  case ALL_CLUSTERS:
900  select_cluster(0);
901  global_data->clear(SHOWN_CLUSTERS);
902  break;
903  }
904 
906 }
907 
908 // ----------------------
909 // store/restore
910 
911 static void store_selected_cluster(ClusterPtr cluster) {
912  int pos = global_data->get_pos(cluster, SHOWN_CLUSTERS);
913  int nextId = global_data->idAtPos(pos+1, SHOWN_CLUSTERS);
914 
915  select_cluster(nextId);
916  global_data->store(cluster->get_ID());
917 }
918 static void store_clusters(AW_window *aww, AffectedClusters affected) {
919  switch (affected) {
920  case SEL_CLUSTER:
921  with_affected_clusters_do(aww->get_root(), affected, true, makeClusterCallback(store_selected_cluster));
922  break;
923  case ALL_CLUSTERS:
924  select_cluster(0);
925  global_data->store_all();
926  break;
927  }
928 
929  update_all(aww);
930 }
931 
932 
933 static void restore_clusters(AW_window *aww) {
934  global_data->restore_all();
935  update_all(aww);
936 }
937 static void swap_clusters(AW_window *aww) {
938  global_data->swap_all();
939  select_cluster(0);
940  update_all(aww);
941 }
942 
943 // ---------------------------------
944 // cluster detection window
945 
947  static AW_window_simple *aws = NULp;
948  if (!aws) {
949  cl_assert(!global_data);
950  global_data = new ClustersData(*weightedFilter);
951 
952  aws = new AW_window_simple;
953  aws->init(aw_root, "DETECT_CLUSTERS", "Detect clusters in tree");
954  aws->load_xfig("di_clusters.fig");
955 
956  aws->on_hide(di_forget_global_data);
957 
958  // -------------------
959  // upper area
960 
961  aws->at("close");
962  aws->callback(AW_POPDOWN);
963  aws->create_button("CLOSE", "CLOSE");
964 
965  aws->at("help");
966  aws->callback(makeHelpCallback("di_clusters.hlp"));
967  aws->create_button("HELP", "HELP");
968 
969  aws->at("max_dist");
970  aws->d_callback(makeWindowCallback(calculate_clusters));
971  aws->create_input_field(AWAR_CLUSTER_MAXDIST, 12);
972 
973  aws->at("min_size");
974  aws->d_callback(makeWindowCallback(calculate_clusters));
975  aws->create_input_field(AWAR_CLUSTER_MINSIZE, 5);
976 
977  aws->at("calculate");
978  aws->callback(calculate_clusters);
979  aws->create_autosize_button("CALC", "Detect clusters");
980 
981  aws->button_length(20);
982  aws->at("tree_name");
983  aws->create_button(NULp, AWAR_DIST_TREE_CURR_NAME);
984 
985  // -------------------
986  // lower area
987 
988  aws->button_length(10);
989 
990  // column 1
991 
992  aws->at("select_rep"); aws->create_toggle(AWAR_CLUSTER_SELECTREP);
993  aws->at("mark"); aws->callback(makeWindowCallback(mark_clusters, SEL_CLUSTER, true)); aws->create_button("MARK", "Mark");
994  aws->at("auto_mark"); aws->create_toggle(AWAR_CLUSTER_AUTOMARK);
995 
996  aws->at("mark_what");
997  aws->create_option_menu(AWAR_CLUSTER_MARKREP, true);
998  aws->insert_default_option("cluster w/o repr.", "d", CMM_ALL_BUT_REP);
999  aws->insert_option ("whole cluster", "b", CMM_ALL);
1000  aws->insert_option ("only representative", "s", CMM_ONLY_REP);
1001  aws->update_option_menu();
1002 
1003  aws->at("mark_all"); aws->callback(makeWindowCallback(mark_clusters, ALL_CLUSTERS, true)); aws->create_button("MARKALL", "Mark all");
1004 
1005  // column 2
1006 
1007  aws->button_length(18);
1008 
1009  aws->at("group"); aws->callback(popup_group_clusters_window); aws->create_button("GROUP", "Cluster groups..");
1010 
1011  aws->at("sort");
1012  aws->create_option_menu(AWAR_CLUSTER_ORDER, true);
1013  aws->insert_default_option("by mean distance", "d", SORT_BY_MEANDIST);
1014  aws->insert_option ("by min bases used", "b", SORT_BY_MIN_BASES);
1015  aws->insert_option ("by size", "s", SORT_BY_CLUSTERSIZE);
1016  aws->insert_option ("by tree position", "p", SORT_BY_TREEPOSITION);
1017  aws->insert_option ("by min distance", "i", SORT_BY_MIN_DIST);
1018  aws->insert_option ("by max distance", "x", SORT_BY_MAX_DIST);
1019  aws->insert_option ("reverse", "r", SORT_REVERSE);
1020  aws->update_option_menu();
1021 
1022  // store/restore
1023 
1024  aws->at("store_all"); aws->callback(makeWindowCallback(store_clusters, ALL_CLUSTERS)); aws->create_button("STOREALL", "Store all");
1025  aws->at("store"); aws->callback(makeWindowCallback(store_clusters, SEL_CLUSTER)); aws->create_button("STORESEL", "Store selected");
1026  aws->at("restore"); aws->callback(restore_clusters); aws->create_button("RESTORE", AWAR_CLUSTER_RESTORE_LABEL);
1027  aws->at("swap"); aws->callback(swap_clusters); aws->create_button("Swap", "Swap stored");
1028 
1029  // column 4
1030 
1031  aws->at("clear"); aws->callback(makeWindowCallback(delete_clusters, ALL_CLUSTERS)); aws->create_button("CLEAR", "Clear list");
1032  aws->at("delete"); aws->callback(makeWindowCallback(delete_clusters, SEL_CLUSTER)); aws->create_button("DEL", "Delete selected");
1033 
1034  // --------------------
1035  // clusterlist
1036 
1037  aws->at("cluster_list");
1038  global_data->clusterList = aws->create_selection_list(AWAR_CLUSTER_SELECTED, true);
1040 
1043  sort_order_changed_cb(aw_root);
1044  }
1045 
1046  return aws;
1047 }
1048 
1050  aw_root->awar_float(AWAR_CLUSTER_MAXDIST, 3.0, def)->set_minmax(0.0, 100.0);
1051  aw_root->awar_int (AWAR_CLUSTER_MINSIZE, 7, def)->set_minmax(2, INT_MAX);
1052  aw_root->awar_int (AWAR_CLUSTER_AUTOMARK, 1, def);
1054  aw_root->awar_int (AWAR_CLUSTER_SELECTREP, 1, def);
1055 
1056  aw_root->awar_int (AWAR_CLUSTER_ORDER, SORT_BY_MEANDIST, def);
1057  aw_root->awar_string(AWAR_CLUSTER_RESTORE_LABEL, "None stored", def);
1058 
1061 
1062  aw_root->awar_int (AWAR_CLUSTER_GROUP_IDENTITY, 100, def)->set_minmax(1, 100);
1063  aw_root->awar_int (AWAR_CLUSTER_GROUP_PREFIX_MATCH, 1, def);
1064  aw_root->awar_string(AWAR_CLUSTER_GROUP_EXAMPLE, "", def);
1065 
1070 
1071  aw_root->awar_int(AWAR_TREE_REFRESH, 0, db);
1072 
1073  update_example(aw_root);
1074 }
1075 
GBDATA * get_representative() const
GBDATA * get_gb_main() const
#define AWAR_CLUSTER_SELECTREP
Definition: DI_clusters.cxx:43
const DBItemSet & get_members() const
static void mark_cluster(ClusterPtr cluster, ClusterMarkMode markRep)
~GroupTreeRoot() OVERRIDE
#define AWAR_CLUSTER_SELECTED
Definition: DI_clusters.cxx:58
size_t count(ClusterSubset subset)
const char * get_list_display(const DisplayFormat *format) const
static void save_results(ClusterTreeRoot *tree)
char * originalGroupName(const char *groupname)
double get_mean_distance() const
static void update_all(AW_window *aww)
string concatenate_name_parts(const list< string > &namepart)
return string(buffer, length)
#define AWAR_CLUSTER_GROUP_PREFIX_MATCH
Definition: DI_clusters.cxx:54
static void select_representative(ClusterPtr cluster)
unsigned deleted
#define AWAR_CLUSTER_GROUP_EXISTING
Definition: DI_clusters.cxx:50
void changeSortOrder(ClusterOrder newOrder)
#define DEFINE_TREE_RELATIVES_ACCESSORS(TreeType)
Definition: TreeNode.h:572
GroupTree(GroupTreeRoot *root)
void update_cluster_selection_list()
static void select_cluster(ID id)
ID idAtPos(int pos, ClusterSubset subset)
#define AWAR_CLUSTER_MARKREP
Definition: DI_clusters.cxx:42
#define AWAR_CLUSTER_GROUP_IDENTITY
Definition: DI_clusters.cxx:52
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
long read_int() const
Definition: AW_awar.cxx:187
AW_awar * set_minmax(float min, float max)
Definition: AW_awar.cxx:532
static void save_results_recursive(ClusterTree *subtree)
#define AWAR_DIST_ALIGNMENT
Definition: di_awars.hxx:21
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
unsigned overwritten
STL namespace.
void init_tree() OVERRIDE
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
#define AWAR_CLUSTER_GROUP_NOTFOUND
Definition: DI_clusters.cxx:51
~GroupTree() OVERRIDE
Group_NotFound
Definition: DI_clusters.cxx:71
bool isNull() const
test if SmartPtr is NULp
Definition: smartptr.h:248
float tagged_rate() const
unsigned created
static void delete_clusters(AW_window *aww, AffectedClusters affected)
bool GBT_is_alignment_protein(GBDATA *gb_main, const char *alignment_name)
Definition: adali.cxx:757
void update_description(const ARB_countedTree *ct)
static void restore_clusters(AW_window *aww)
FILE * seq
Definition: rns.c:46
#define cb(action)
#define DOWNCAST(totype, expr)
Definition: downcast.h:141
static void update_cluster_sellist()
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:234
#define AWAR_CLUSTER_GROUP_PREFIX
Definition: DI_clusters.cxx:53
void add(ClusterPtr clus, ClusterSubset subset)
const char * read_char_pntr() const
Definition: AW_awar.cxx:171
string generate_group_name(ClusterPtr cluster, const GroupTree *group_node)
POS_TREE1 * get_father() const
Definition: probe_tree.h:49
GroupTree * find_best_matching_subtree(ClusterPtr cluster)
static void update_cluster_group(ClusterPtr cluster, GroupBuilder *groupBuilder)
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
HasntCurrentClusterPrefix(const GroupBuilder &builder_)
std::string get_upgroup_info(const ARB_countedTree *ct, const ARB_tree_predicate &keep_group_name)
GBDATA * GB_create_container(GBDATA *father, const char *key)
Definition: arbdb.cxx:1803
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
static void store_selected_cluster(ClusterPtr cluster)
static void update_example(AW_root *aw_root)
DECLARE_CBTYPE_FVV_AND_BUILDERS(ClusterCallback, void, ClusterPtr)
AffectedClusters
Definition: DI_clusters.cxx:86
ARB_ERROR get_error() const
#define AWAR_CLUSTER_GROUP_WHAT
Definition: DI_clusters.cxx:49
std::set< GBDATA * > DBItemSet
Definition: dbitem_set.h:22
AW_awar * awar_float(const char *var_name, float default_value=0.0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:560
AW_root * get_aw_root() const
AW_window * DI_create_cluster_detection_window(AW_root *aw_root, WeightedFilter *weightedFilter)
#define AWAR_CLUSTER_GROUP_SUFFIX
Definition: DI_clusters.cxx:55
static void select_cluster_cb(AW_root *aw_root)
const ClusterIDs & get_clusterIDs(ClusterSubset subset)
ClusterPtr get_bad_cluster() const
static void group_clusters(AW_window *, Group_Action action)
void show_message()
std::vector< ID > ClusterIDs
void touch()
Definition: AW_awar.cxx:210
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define AWAR_TREE_REFRESH
bool is_root_node() const
Definition: TreeNode.h:391
Group_Action
Definition: DI_clusters.cxx:66
ARB_ERROR save_modified_tree()
int32_t ID
void store(ID id)
#define AWAR_SPECIES_NAME
DBItemSet::const_iterator DBItemSetIter
Definition: dbitem_set.h:23
ClusterMarkMode
Group_Existing
Definition: DI_clusters.cxx:77
ID get_ID() const
#define AWAR_CLUSTER_GROUP_EXAMPLE
Definition: DI_clusters.cxx:56
static SearchTree * tree[SEARCH_PATTERNS]
Definition: ED4_search.cxx:629
char * read_string() const
Definition: AW_awar.cxx:201
static void calculate_clusters(AW_window *aww)
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
static void store_clusters(AW_window *aww, AffectedClusters affected)
bool is_cluster(ID id)
void clear(ClusterSubset subset)
static void swap_clusters(AW_window *aww)
float read_float() const
Definition: AW_awar.cxx:180
void remove(ClusterPtr clus, ClusterSubset subset)
static int with_affected_clusters_do(AW_root *aw_root, AffectedClusters affected, bool warn_if_none_affected, ClusterCallback cb)
static void update_restore_label(AW_window *aww)
bool exist() const
void accept_proposed(bool accept)
#define AWAR_DIST_TREE_CURR_NAME
Definition: di_awars.hxx:28
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
GroupBuilder(GBDATA *gb_main_, Group_Action action_)
AliView * create_aliview(const char *aliname, GB_ERROR &error) const
Definition: GUI_aliview.cxx:67
void DI_create_cluster_awars(AW_root *aw_root, AW_default def, AW_default db)
xml element
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:32
ClusterIDs::const_iterator ClusterIDsIter
void GB_write_flag(GBDATA *gbd, long flag)
Definition: arbdb.cxx:2737
static void mark_clusters(AW_window *, AffectedClusters affected, bool warn_if_none_affected)
#define OVERRIDE
Definition: cxxforward.h:93
ClusterPtr clusterWithID(ID id) const
#define concat(a, b)
Definition: ed4_class.hxx:13
void subtitle(const char *stitle)
Definition: arb_progress.h:263
#define cl_assert(cond)
#define AWAR_CLUSTER_ORDER
Definition: DI_clusters.cxx:44
void update_group(ClusterPtr cluster)
Group_What
Definition: DI_clusters.cxx:61
#define di_assert(cond)
Definition: DI_clusters.cxx:31
void aw_message(const char *msg)
Definition: AW_status.cxx:932
bool matches_current_prefix(const char *groupname) const
AW_root * get_root()
Definition: aw_window.hxx:348
static void delete_selected_cluster(ClusterPtr cluster)
#define NULp
Definition: cxxforward.h:97
GB_ERROR GBT_write_name_to_groupData(GBDATA *gb_group, bool createNameEntry, const char *new_group_name, bool pedantic)
Definition: adtree.cxx:279
bool is_leaf() const
Definition: probe_tree.h:67
size_t get_member_count() const
#define AWAR_CLUSTER_RESTORE_LABEL
Definition: DI_clusters.cxx:59
GB_ERROR write_string(const char *aw_string)
#define AWAR_CLUSTER_AUTOMARK
Definition: DI_clusters.cxx:41
static ClustersData * global_data
Definition: DI_clusters.cxx:88
const char * GBT_get_name(GBDATA *gb_item)
Definition: aditem.cxx:446
map< string, GroupTree * > Species2Tip
unsigned restored
void GBT_mark_all(GBDATA *gb_main, int flag)
Definition: aditem.cxx:291
unsigned get_tagged_count() const
WeightedFilter & weighted_filter
static void sort_order_changed_cb(AW_root *aw_root)
GB_transaction ta(gb_var)
GB_ERROR GBT_write_int(GBDATA *gb_container, const char *fieldpath, long content)
Definition: adtools.cxx:471
GBDATA * gb_main
Definition: adname.cxx:33
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
AW_selection_list * clusterList
void tag_leaf()
static void di_forget_global_data(AW_window *)
Definition: DI_clusters.cxx:92
#define AWAR_CLUSTER_MINSIZE
Definition: DI_clusters.cxx:40
const char * get_group_name() const
Definition: TreeNode.h:445
static void accept_proposed_names(ClusterPtr cluster, bool accept)
GB_ERROR write_int(long aw_int)
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
static void popup_group_clusters_window(AW_window *aw_clusterList)
unsigned skipped
const char * label
#define AWAR_CLUSTER_MAXDIST
Definition: DI_clusters.cxx:39
ClusterOrder
void mark_all_members(ClusterMarkMode mmode) const