ARB
AWT_TreeAwars.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : AWT_TreeAwars.cxx //
4 // Purpose : tree awar registry //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in January 2014 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // =============================================================== //
11 
12 #include "awt_TreeAwars.hxx"
13 
14 #include <arbdbt.h>
15 #include <ad_cb.h>
16 
17 #include <arb_global_defs.h>
18 
19 #include <aw_awar.hxx>
20 #include <aw_root.hxx>
21 #include <aw_global_awars.hxx>
22 
23 #include <set>
24 #include <cstddef>
25 
26 #define awt_assert(cond) arb_assert(cond)
27 
35  mutable AW_awar *awar;
36  GBDATA *gb_tree;
37  TreeAwarCallback cb;
38  mutable bool triggerOnDataChange;
39 
40 public:
41  BoundTreeAwarCallback(AW_awar *awar_, const TreeAwarCallback& cb_, bool triggerIfTreeDataChanges);
43 
44  void bind_tree_callback();
45  void call(bool treeDataChanged) { cb(awar, treeDataChanged); }
46 
47  void rename_if(const char *oldname, const char *newname) const {
48  if (strcmp(awar->read_char_pntr(), oldname) == 0) {
49  awar->write_string(newname);
50  }
51  }
52 
53  bool is_less_than(const BoundTreeAwarCallback& other) const {
54  ptrdiff_t diff = (const char*)awar - (const char*)other.awar;
55  return diff<0;
56  }
57 
58  void tree_lost() { gb_tree = NULp; }
59 };
60 
62 
63 inline bool operator<(const BoundTreeAwarCallbackPtr& bc1, const BoundTreeAwarCallbackPtr& bc2) {
64  return bc1->is_less_than(*bc2);
65 }
66 
67 typedef std::set<BoundTreeAwarCallbackPtr> BoundTreeAwarCallbacks;
68 
71 class TreeAwarRegistry : virtual Noncopyable {
72  GBDATA *gb_main;
73  BoundTreeAwarCallbacks callbacks;
74 
75 public:
76  TreeAwarRegistry(GBDATA *gb_main_);
77 
79 
80  GBDATA *get_gb_main() { return gb_main; }
81  void add(BoundTreeAwarCallbackPtr bcb) { callbacks.insert(bcb); }
82 
83  void tree_renamed(const char *oldname, const char *newname);
84 };
85 
87 
88 static void destroy_TreeAwarRegistry() {
89  TreeAwarRegistry::SINGLETON.setNull();
90 }
91 
92 // --------------------------
93 // BoundTreeAwarCallback
94 
96  if (cbtype == GB_CB_DELETE) {
97  tac->tree_lost();
98  }
99  tac->call(true);
100 }
102  tac->bind_tree_callback();
103  tac->call(false);
104 }
105 
107  if (triggerOnDataChange) {
108  DatabaseCallback dbcb = makeDatabaseCallback(TreeDataChanged_cb, this);
109  {
110  GBDATA *gb_main = TreeAwarRegistry::SINGLETON->get_gb_main();
111  GB_transaction ta(gb_main);
112  if (gb_tree) {
114  gb_tree = NULp;
115  }
116 
117  char *treename = awar->read_string();
118  gb_tree = GBT_find_tree(gb_main, treename);
119 
120  if (gb_tree) GB_add_callback(gb_tree, GB_CB_CHANGED_OR_DELETED, dbcb);
121  free(treename);
122  }
123  }
124 }
125 
126 BoundTreeAwarCallback::BoundTreeAwarCallback(AW_awar *awar_, const TreeAwarCallback& cb_, bool triggerIfTreeDataChanges)
127  : awar(awar_),
128  gb_tree(NULp),
129  cb(cb_),
130  triggerOnDataChange(triggerIfTreeDataChanges)
131 {
132  awar->add_callback(makeRootCallback(TreeAwarChanged_cb, this));
134 }
136  awar->remove_callback(makeRootCallback(TreeAwarChanged_cb, this));
137 
138  // remove DB callback w/o triggering it:
139  char *old = awar->read_string();
140  awar->write_string("");
142  awar->write_string(old);
143  free(old);
144 }
145 
146 // --------------------------
147 // TreeAwarRegistry
148 
149 static void tree_renamed_cb(AW_root *aw_root) {
150  AW_awar *awar_renamed = aw_root->awar(AWAR_ARB_TREE_RENAMED);
151  char *name_change = awar_renamed->read_string();
152 
153  if (name_change[0]) {
154  char *equal = strchr(name_change, '=');
155  GB_ERROR error = NULp;
156  if (!equal) error = "Expected '=' missing";
157  else {
158  equal[0] = 0;
159 
160  const char *oldname = name_change;
161  const char *newname = equal+1;
162  TreeAwarRegistry::SINGLETON->tree_renamed(oldname, newname);
163  }
164 
165  if (error) {
166  fprintf(stderr, "Warning: Cannot handle invalid tree-name-change ('%s'; %s)",
167  awar_renamed->read_char_pntr(), error);
168  }
169  }
170 }
171 
173  : gb_main(gb_main_)
174 {
175  // uses global awar AWAR_ARB_TREE_RENAMED to synchronize between multiple ARB apps
177  GB_atclose_callback(gb_main_, makeDatabaseCallback(destroy_TreeAwarRegistry));
178 }
179 
180 void TreeAwarRegistry::tree_renamed(const char *oldname, const char *newname) {
181  for (BoundTreeAwarCallbacks::iterator bcb = callbacks.begin(); bcb != callbacks.end(); ++bcb) {
182  (*bcb)->rename_if(oldname, newname);
183  }
184 }
185 
186 // -------------------
187 // interface
188 
197  awt_assert(gbmain);
198  if (TreeAwarRegistry::SINGLETON.isSet()) {
199  if (TreeAwarRegistry::SINGLETON->get_gb_main() != gbmain) {
200  GBK_terminate("double init of TreeAwarRegistry with different gbmain");
201  }
202  }
203  else {
204  TreeAwarRegistry::SINGLETON = new TreeAwarRegistry(gbmain);
205  }
206 }
207 
208 void AWT_registerTreeAwarCallback(AW_awar *awar, const TreeAwarCallback& tacb, bool triggerIfTreeDataChanges) {
218  TreeAwarRegistry::SINGLETON->add(new BoundTreeAwarCallback(awar, tacb, triggerIfTreeDataChanges));
219 }
220 
221 static void null_cb() {}
226  AWT_registerTreeAwarCallback(awar, makeTreeAwarCallback(null_cb), false);
227 }
228 
229 static void announce_renamed(const char *oldname, const char *newname) {
231  awar_renamed->write_string(GBS_global_string("%s=%s", oldname, newname)); // triggers tree_renamed_cb (in this and all other ARB apps)
232 }
233 
234 void AWT_announce_tree_renamed(const char *oldname, const char *newname) { announce_renamed(oldname, newname); }
236 
const char * GB_ERROR
Definition: arb_core.h:25
static void TreeDataChanged_cb(UNFIXED, BoundTreeAwarCallback *tac, GB_CB_TYPE cbtype)
bool operator<(const BoundTreeAwarCallbackPtr &bc1, const BoundTreeAwarCallbackPtr &bc2)
BoundTreeAwarCallback(AW_awar *awar_, const TreeAwarCallback &cb_, bool triggerIfTreeDataChanges)
void GB_atclose_callback(GBDATA *gbd, const DatabaseCallback &atClose)
Definition: ad_cb.cxx:458
void add(BoundTreeAwarCallbackPtr bcb)
GB_ERROR GB_add_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:356
void AWT_registerTreeAwarSimple(AW_awar *awar)
void AWT_announce_tree_renamed(const char *oldname, const char *newname)
static void null_cb()
#define NO_TREE_SELECTED
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
void AWT_registerTreeAwarCallback(AW_awar *awar, const TreeAwarCallback &tacb, bool triggerIfTreeDataChanges)
void setNull()
set SmartPtr to NULp
Definition: smartptr.h:251
#define cb(action)
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:234
struct Unfixed_cb_parameter * UNFIXED
Definition: cb_base.h:15
const char * read_char_pntr() const
Definition: AW_awar.cxx:171
static AW_root * SINGLETON
Definition: aw_root.hxx:102
static int diff(int v1, int v2, int v3, int v4, int st, int en)
Definition: ClustalV.cxx:534
#define AWAR_ARB_TREE_RENAMED
static void announce_renamed(const char *oldname, const char *newname)
Generic smart pointer.
Definition: smartptr.h:149
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:463
void AWT_announce_tree_deleted(const char *name)
static void destroy_TreeAwarRegistry()
bool is_less_than(const BoundTreeAwarCallback &other) const
static void error(const char *msg)
Definition: mkptypes.cxx:96
std::set< BoundTreeAwarCallbackPtr > BoundTreeAwarCallbacks
char * read_string() const
Definition: AW_awar.cxx:201
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
AW_awar * remove_callback(const RootCallback &cb)
Definition: AW_awar.cxx:527
static void TreeAwarChanged_cb(UNFIXED, BoundTreeAwarCallback *tac)
TreeAwarRegistry(GBDATA *gb_main_)
SmartPtr< BoundTreeAwarCallback > BoundTreeAwarCallbackPtr
void rename_if(const char *oldname, const char *newname) const
#define awt_assert(cond)
void GB_remove_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:360
static void tree_renamed_cb(AW_root *aw_root)
#define NULp
Definition: cxxforward.h:97
GB_ERROR write_string(const char *aw_string)
GBDATA * GBT_find_tree(GBDATA *gb_main, const char *tree_name)
Definition: adtree.cxx:947
GB_transaction ta(gb_var)
GBDATA * gb_main
Definition: adname.cxx:33
GB_CB_TYPE
Definition: arbdb_base.h:46
GBDATA * get_gb_main()
GBDATA * get_gb_main(DbSel db)
Definition: merge.hxx:88
void AWT_initTreeAwarRegistry(GBDATA *gbmain)
static SmartPtr< TreeAwarRegistry > SINGLETON
void call(bool treeDataChanged)
void tree_renamed(const char *oldname, const char *newname)