Go to the documentation of this file.00001
00002 #include "vgui_parent_child_link.h"
00003
00004
00005
00006
00007
00008 #include <vcl_cassert.h>
00009 #include <vcl_iostream.h>
00010 #include <vcl_vector.h>
00011 #include <vcl_set.h>
00012
00013 #include <vgui/vgui_event.h>
00014 #include <vgui/vgui_tableau.h>
00015 #include <vgui/vgui_tableau_sptr.h>
00016 #include <vgui/vgui_macro.h>
00017
00018
00019
00020
00021
00022
00023 #define cache_parents 1
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 struct vgui_parent_child_link_impl
00057 {
00058
00059
00060 typedef vcl_set<void *> all_t;
00061 static all_t* all;
00062 static int all_refs;
00063
00064 inline vgui_parent_child_link_impl(vgui_tableau *p_, vgui_tableau *c_);
00065 inline ~vgui_parent_child_link_impl();
00066
00067
00068 inline void assign(vgui_tableau *t);
00069
00070
00071 vgui_tableau *parent() const { return p; }
00072 vgui_tableau *child () const { return c; }
00073
00074
00075
00076 inline void acquire();
00077 inline void release();
00078
00079 private:
00080 vgui_tableau *p;
00081 vgui_tableau *c;
00082 int use_count;
00083
00084
00085
00086
00087
00088 static inline void link (vgui_tableau *p, vgui_tableau *c);
00089 static inline void unlink(vgui_tableau *p, vgui_tableau *c);
00090 };
00091
00092
00093 vcl_set<void*>* vgui_parent_child_link_impl::all = 0;
00094 int vgui_parent_child_link_impl::all_refs = -1;
00095
00096 void vgui_parent_child_link_impl::acquire()
00097 {
00098 ++ use_count;
00099 }
00100
00101 void vgui_parent_child_link_impl::release()
00102 {
00103 assert(use_count > 0);
00104
00105 if (-- use_count == 0)
00106 delete this;
00107 }
00108
00109 void vgui_parent_child_link_impl::unlink(vgui_tableau *p, vgui_tableau *c)
00110 {
00111 #if cache_parents
00112 if (c) {
00113 vcl_vector<vgui_tableau*> &vec = c->vgui_parent_child_link_data::parents;
00114 for (vcl_vector<vgui_tableau*>::iterator i=vec.begin(); i!=vec.end(); ++i) {
00115 if (*i == p) {
00116 vec.erase(i);
00117 break;
00118 }
00119 }
00120 }
00121 #endif
00122 }
00123
00124 void vgui_parent_child_link_impl::link(vgui_tableau *p, vgui_tableau *c)
00125 {
00126 #if cache_parents
00127 if (c)
00128 c->vgui_parent_child_link_data::parents.push_back(p);
00129 #endif
00130 }
00131
00132 vgui_parent_child_link_impl::vgui_parent_child_link_impl(vgui_tableau *p_, vgui_tableau *c_)
00133 : p(p_)
00134 , c(c_)
00135 , use_count(0)
00136 {
00137 if (! p) {
00138 vgui_macro_warning << "parent is null\n";
00139 assert(false);
00140 }
00141
00142 if (c)
00143 c->ref();
00144
00145
00146 if (all == 0) {
00147 #ifdef DEBUG
00148 vcl_cerr << __FILE__ " : CREATING parent_child_link cache\n";
00149 #endif
00150 all = new all_t;
00151 all_refs = 0;
00152 }
00153 ++all_refs;
00154 all->insert(this);
00155
00156
00157 if (p == c) {
00158 vgui_macro_warning << "parent and child are equal\n";
00159 assert(false);
00160 }
00161
00162 link(p, c);
00163 }
00164
00165 vgui_parent_child_link_impl::~vgui_parent_child_link_impl()
00166 {
00167 unlink(p, c);
00168
00169 if (c)
00170 c->unref();
00171
00172
00173 vcl_set<void*>::iterator i = all->find(this);
00174 assert(i != all->end());
00175 all->erase(i);
00176 if (--all_refs == 0) {
00177 #ifdef DEBUG
00178 vcl_cerr << __FILE__ " : DELETING parent_child_link cache\n";
00179 #endif
00180 delete all;
00181 all = 0;
00182 }
00183 }
00184
00185 void vgui_parent_child_link_impl::assign(vgui_tableau *t)
00186 {
00187 if (t == c)
00188 return;
00189
00190 if (t == p) {
00191 vgui_macro_warning << "cannot assign() a parent_child_link\'s parent to its child\n";
00192 assert(false);
00193 }
00194
00195 unlink(p, c);
00196
00197 if (t)
00198 t->ref();
00199
00200
00201
00202
00203 vgui_tableau *old_c = c;
00204
00205 c = t;
00206
00207 link(p, c);
00208
00209
00210 if (old_c)
00211 old_c->unref();
00212 }
00213
00214
00215
00216 vgui_parent_child_link::vgui_parent_child_link(vgui_tableau *p)
00217 {
00218 pimpl = new vgui_parent_child_link_impl(p, 0);
00219 pimpl->acquire();
00220 }
00221
00222 vgui_parent_child_link::vgui_parent_child_link(vgui_tableau *p,
00223 vgui_tableau_sptr const &c)
00224 {
00225 pimpl = new vgui_parent_child_link_impl(p, c.operator->());
00226 pimpl->acquire();
00227 }
00228
00229 vgui_parent_child_link::vgui_parent_child_link(vgui_parent_child_link const &that)
00230 {
00231 pimpl = that.pimpl;
00232
00233 if (pimpl)
00234 pimpl->acquire();
00235 }
00236
00237 vgui_parent_child_link::~vgui_parent_child_link()
00238 {
00239 if (pimpl)
00240 pimpl->release();
00241
00242 pimpl = 0;
00243 }
00244
00245 vgui_parent_child_link &vgui_parent_child_link::operator=(vgui_parent_child_link const &that)
00246 {
00247 if (pimpl != that.pimpl) {
00248 if (that.pimpl)
00249 that.pimpl->acquire();
00250
00251 if (pimpl)
00252 pimpl->release();
00253
00254 pimpl = that.pimpl;
00255 }
00256
00257 return *this;
00258 }
00259
00260 vgui_tableau_sptr vgui_parent_child_link::parent() const
00261 {
00262 return pimpl ? pimpl->parent() : 0;
00263 }
00264
00265 vgui_tableau_sptr vgui_parent_child_link::child() const
00266 {
00267 return pimpl ? pimpl->child () : 0;
00268 }
00269
00270 bool vgui_parent_child_link::operator==(vgui_tableau_sptr const &t) const
00271 {
00272 return child() == t;
00273 }
00274
00275 void vgui_parent_child_link::assign(vgui_tableau_sptr const &t)
00276 {
00277 if (pimpl)
00278 pimpl->assign(t.operator->());
00279 else
00280 {
00281 vgui_macro_warning << "attempted assign() to empty parent_child_link.\n"
00282 << "t = " << t << vcl_endl;
00283 assert(false);
00284 }
00285 }
00286
00287 bool vgui_parent_child_link::handle(vgui_event const &e)
00288 {
00289 if (!pimpl) return false;
00290 vgui_tableau* c = pimpl->child();
00291 if (!c) return false;
00292
00293 return c->handle(e);
00294 }
00295
00296 vgui_parent_child_link::operator vgui_parent_child_link::safe_bool() const
00297 {
00298 return (pimpl && (pimpl->child() != 0))? VCL_SAFE_BOOL_TRUE : 0;
00299 }
00300
00301 bool vgui_parent_child_link::operator!() const
00302 {
00303 return (pimpl && (pimpl->child() != 0))? false : true;
00304 }
00305
00306 vgui_parent_child_link::operator vgui_tableau_sptr() const
00307 {
00308 return pimpl ? pimpl->child() : 0;
00309 }
00310
00311 vgui_tableau *vgui_parent_child_link::operator->() const
00312 {
00313 return pimpl ? pimpl->child() : 0;
00314 }
00315
00316 vcl_ostream & operator<<(vcl_ostream &os, vgui_parent_child_link const &s)
00317 {
00318
00319
00320 return os << "vgui_parent_child_link("
00321 << vcl_flush
00322 << static_cast<void*>( s.parent().operator->() ) << ", "
00323 << vcl_flush
00324 << static_cast<void*>( s.child ().operator->() ) << ')'
00325 << vcl_flush;
00326 }
00327
00328
00329
00330 void vgui_parent_child_link::get_children_of(vgui_tableau_sptr const& tab,
00331 vcl_vector<vgui_tableau_sptr> *children)
00332 {
00333 for (vcl_set<void*>::iterator i=vgui_parent_child_link_impl::all->begin();
00334 i!=vgui_parent_child_link_impl::all->end(); ++i)
00335 {
00336 vgui_parent_child_link_impl *ptr = static_cast<vgui_parent_child_link_impl*>(*i);
00337 if ( ptr->parent() == tab.operator->() )
00338 children->push_back( ptr->child() );
00339 }
00340 }
00341
00342 void vgui_parent_child_link::get_parents_of (vgui_tableau_sptr const& tab,
00343 vcl_vector<vgui_tableau_sptr> *parents)
00344 {
00345 #if cache_parents
00346 vcl_vector<vgui_tableau*> const &vec
00347 = tab->vgui_parent_child_link_data::parents;
00348 for (unsigned i=0; i<vec.size(); ++i)
00349 parents->push_back(vec[i]);
00350 #else
00351 for (vcl_set<void*>::iterator i=vgui_parent_child_link_impl::all->begin();
00352 i!=vgui_parent_child_link_impl::all->end(); ++i)
00353 {
00354 vgui_parent_child_link_impl *ptr = static_cast<vgui_parent_child_link_impl*>(*i);
00355 if ( ptr->child() == tab.operator->() )
00356 children->push_back( ptr->parent() );
00357 }
00358 #endif
00359 }
00360
00361 void vgui_parent_child_link::replace_child_everywhere(vgui_tableau_sptr const &old_child,
00362 vgui_tableau_sptr const &new_child)
00363 {
00364 #ifdef DEBUG
00365 vcl_cerr << "vgui_parent_child_link::replace_child_everywhere\n"
00366 << " old_child : " << old_child->pretty_name() << '\t'
00367 << " new child : " << new_child->pretty_name() << '\n';
00368 #endif
00369
00370 if (old_child == new_child)
00371 vcl_cerr << "vgui_parent_child_link::replace_child_everywhere: old_child == new_child\n";
00372
00373 for (vcl_set<void*>::iterator i=vgui_parent_child_link_impl::all->begin();
00374 i!=vgui_parent_child_link_impl::all->end(); ++i)
00375 {
00376 vgui_parent_child_link_impl *ptr
00377 = static_cast<vgui_parent_child_link_impl*>(*i);
00378
00379 #ifdef DEBUG
00380 vcl_cerr << " parent_child_link\t"
00381 << "parent : " << ptr->parent()->pretty_name()
00382 << "\tchild : ";
00383 if (! ptr->child())
00384 vcl_cerr << "0\n";
00385 else
00386 vcl_cerr << ptr->child()->pretty_name() << '\n';
00387 #endif
00388
00389 if ( ptr->child() == old_child.operator->() ) {
00390 assert(ptr->parent() != new_child.operator->() );
00391 #ifdef DEBUG
00392 vcl_cerr << " replaced by: " << ptr->child() << '\n';
00393 #endif
00394 ptr->parent()->notify_replaced_child(old_child, new_child);
00395 ptr->assign(new_child.operator->());
00396 }
00397 }
00398 }