1 /* 2 * ContactTree 3 * 4 * Copyright (C) 2002 Barnaby Gray <barnaby@beedesign.co.uk> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <cstdlib> 23 24 #include "ContactTree.h" 25 #include "events.h" 26 27 namespace ICQ2000 { 28 29 using std::string; 30 31 #define ITERATE_CONTACTS_BEGIN \ 32 iterator curr = begin(); \ 33 while (curr != end()) { 34 35 #define ITERATE_CONTACTS_END \ 36 ++curr; \ 37 } 38 39 #define ITERATE_GROUPS_BEGIN \ 40 iterator curr = m_groups.begin(); \ 41 while (curr != m_groups.end()) { 42 43 #define ITERATE_GROUPS_END \ 44 ++curr; \ 45 } 46 47 #define CONST_ITERATE_GROUPS_BEGIN \ 48 const_iterator curr = m_groups.begin(); \ 49 while (curr != m_groups.end()) { 50 51 #define CONST_ITERATE_GROUPS_END \ 52 ++curr; \ 53 } 54 55 // ============================================================================ 56 // ContactTree Group object 57 // ============================================================================ 58 _ContactTree_Group(const std::string & l,unsigned short id)59 _ContactTree_Group::_ContactTree_Group(const std::string& l, unsigned short id) 60 : m_id(id), m_label(l) 61 { } 62 _ContactTree_Group()63 _ContactTree_Group::_ContactTree_Group() 64 : m_id(0), m_label("") 65 { } 66 _ContactTree_Group(const _ContactTree_Group & gp)67 _ContactTree_Group::_ContactTree_Group(const _ContactTree_Group& gp) 68 : m_crefs( gp.m_crefs ), m_id( gp.m_id ), m_label( gp.m_label ) 69 { } 70 get_id() const71 unsigned short _ContactTree_Group::get_id() const 72 { 73 return m_id; 74 } 75 get_label() const76 string _ContactTree_Group::get_label() const 77 { 78 return m_label; 79 } 80 set_label(const string & l)81 void _ContactTree_Group::set_label(const string& l) 82 { 83 if (m_label == l) return; 84 m_label = l; 85 GroupChangeEvent ev( *this ); 86 contactlist_signal.emit( &ev ); 87 } 88 operator [](unsigned int uin)89 ContactRef _ContactTree_Group::operator[](unsigned int uin) 90 { 91 return lookup_uin(uin); 92 } 93 lookup_uin(unsigned int uin)94 ContactRef _ContactTree_Group::lookup_uin(unsigned int uin) 95 { 96 if (m_crefs.count(uin) != 0) return (*(m_crefs.find(uin))).second; 97 return NULL; 98 } 99 lookup_mobile(const string & m)100 ContactRef _ContactTree_Group::lookup_mobile(const string& m) 101 { 102 ITERATE_CONTACTS_BEGIN 103 if ((*curr)->getNormalisedMobileNo() == m) return (*curr); 104 ITERATE_CONTACTS_END 105 106 return NULL; 107 } 108 lookup_email(const string & em)109 ContactRef _ContactTree_Group::lookup_email(const string& em) 110 { 111 ITERATE_CONTACTS_BEGIN 112 if ((*curr)->getEmail() == em) return (*curr); 113 ITERATE_CONTACTS_END 114 115 return NULL; 116 } 117 add(ContactRef ct)118 ContactRef _ContactTree_Group::add(ContactRef ct) { 119 m_crefs.insert( std::make_pair(ct->getUIN(), ct) ); 120 121 // fire off signal 122 UserAddedEvent uev( ct, *this ); 123 contactlist_signal.emit( &uev ); 124 125 // connect up contact's status signals to propagate up group 126 ct->status_change_signal.connect( contact_status_change_signal ); 127 ct->userinfo_change_signal.connect( contact_userinfo_change_signal ); 128 129 return ct; 130 } 131 relocate_from(ContactRef ct)132 void _ContactTree_Group::relocate_from(ContactRef ct) { 133 if (m_crefs.count(ct->getUIN()) != 0) 134 m_crefs.erase(ct->getUIN()); 135 } 136 relocate_to(ContactRef ct)137 void _ContactTree_Group::relocate_to(ContactRef ct) { 138 m_crefs.insert( std::make_pair(ct->getUIN(), ct) ); 139 } 140 remove(unsigned int uin)141 void _ContactTree_Group::remove(unsigned int uin) { 142 if (m_crefs.count(uin) != 0) { 143 // first fire off signal 144 UserRemovedEvent uev( m_crefs[uin], *this ); 145 contactlist_signal.emit( &uev ); 146 147 m_crefs.erase(uin); 148 } 149 } 150 empty() const151 bool _ContactTree_Group::empty() const 152 { 153 return m_crefs.empty(); 154 } 155 size() const156 unsigned int _ContactTree_Group::size() const 157 { 158 return m_crefs.size(); 159 } 160 exists(unsigned int uin)161 bool _ContactTree_Group::exists(unsigned int uin) 162 { 163 return (m_crefs.count(uin) != 0); 164 } 165 mobile_exists(const string & m)166 bool _ContactTree_Group::mobile_exists(const string& m) 167 { 168 ITERATE_CONTACTS_BEGIN 169 if ((*curr)->getNormalisedMobileNo() == m) return true; 170 ITERATE_CONTACTS_END 171 return false; 172 } 173 email_exists(const string & em)174 bool _ContactTree_Group::email_exists(const string& em) 175 { 176 ITERATE_CONTACTS_BEGIN 177 if ((*curr)->getEmail() == em) return true; 178 ITERATE_CONTACTS_END 179 return false; 180 } 181 begin()182 _ContactTree_Group::iterator _ContactTree_Group::begin() 183 { 184 return iterator(m_crefs.begin()); 185 } 186 end()187 _ContactTree_Group::iterator _ContactTree_Group::end() 188 { 189 return iterator(m_crefs.end()); 190 } 191 begin() const192 _ContactTree_Group::const_iterator _ContactTree_Group::begin() const 193 { 194 return const_iterator(m_crefs.begin()); 195 } 196 end() const197 _ContactTree_Group::const_iterator _ContactTree_Group::end() const 198 { 199 return const_iterator(m_crefs.end()); 200 } 201 202 // ============================================================================ 203 // ContactTree 204 // ============================================================================ 205 ContactTree()206 ContactTree::ContactTree() { } 207 ContactTree(const ContactTree & ct)208 ContactTree::ContactTree(const ContactTree& ct) 209 : m_groups( ct.m_groups ) 210 { } 211 operator [](unsigned int uin)212 ContactRef ContactTree::operator[](unsigned int uin) 213 { 214 return lookup_uin(uin); 215 } 216 lookup_uin(unsigned int uin)217 ContactRef ContactTree::lookup_uin(unsigned int uin) 218 { 219 ITERATE_GROUPS_BEGIN 220 if ((*curr).exists(uin)) return (*curr).lookup_uin(uin); 221 ITERATE_GROUPS_END 222 return NULL; 223 } 224 lookup_mobile(const std::string & m)225 ContactRef ContactTree::lookup_mobile(const std::string& m) 226 { 227 ITERATE_GROUPS_BEGIN 228 if ((*curr).mobile_exists(m)) return (*curr).lookup_mobile(m); 229 ITERATE_GROUPS_END 230 return NULL; 231 } 232 lookup_email(const std::string & em)233 ContactRef ContactTree::lookup_email(const std::string& em) 234 { 235 ITERATE_GROUPS_BEGIN 236 if ((*curr).email_exists(em)) return (*curr).lookup_email(em); 237 ITERATE_GROUPS_END 238 return NULL; 239 } 240 add_group(const string & l)241 ContactTree::Group& ContactTree::add_group(const string& l) 242 { 243 return add_group(l, get_unique_group_id() ); 244 } 245 add_group(const string & l,unsigned short group_id)246 ContactTree::Group& ContactTree::add_group(const string& l, unsigned short group_id) 247 { 248 if (exists_group(group_id)) { 249 // oops.. trying to add one with a duplicate group_id 250 group_id = get_unique_group_id(); 251 } 252 253 Group gp( l, group_id ); 254 m_groups.push_back(gp); 255 256 // propagate signals up to ContactTree object 257 m_groups.back().contactlist_signal.connect( contactlist_signal ); 258 m_groups.back().contact_status_change_signal.connect( contact_status_change_signal ); 259 m_groups.back().contact_userinfo_change_signal.connect( contact_userinfo_change_signal ); 260 261 // fireoff event 262 GroupAddedEvent ev(m_groups.back()); 263 contactlist_signal.emit( &ev ); 264 265 return m_groups.back(); 266 } 267 remove_group(Group & gp)268 void ContactTree::remove_group(Group& gp) 269 { 270 remove_group(gp.get_id()); 271 } 272 remove_group(unsigned short group_id)273 void ContactTree::remove_group(unsigned short group_id) 274 { 275 ITERATE_GROUPS_BEGIN 276 if ((*curr).get_id() == group_id) { 277 // emit event 278 GroupRemovedEvent ev(*curr); 279 contactlist_signal.emit( &ev ); 280 281 // remove from list 282 m_groups.erase(curr); 283 284 break; 285 } 286 ITERATE_GROUPS_END 287 } 288 exists_group(unsigned short group_id)289 bool ContactTree::exists_group(unsigned short group_id) 290 { 291 ITERATE_GROUPS_BEGIN 292 if ((*curr).get_id() == group_id) return true; 293 ITERATE_GROUPS_END 294 return false; 295 } 296 lookup_group(unsigned short group_id)297 ContactTree::Group& ContactTree::lookup_group(unsigned short group_id) 298 { 299 ITERATE_GROUPS_BEGIN 300 if ((*curr).get_id() == group_id) return (*curr); 301 ITERATE_GROUPS_END 302 return add_group(""); 303 } 304 lookup_group_containing_contact(ContactRef ct)305 ContactTree::Group& ContactTree::lookup_group_containing_contact(ContactRef ct) 306 { 307 unsigned int uin = ct->getUIN(); 308 ITERATE_GROUPS_BEGIN 309 if ((*curr).exists(uin)) return (*curr); 310 ITERATE_GROUPS_END 311 return add_group(""); 312 } 313 relocate_contact(ContactRef ct,Group & from,Group & to)314 void ContactTree::relocate_contact(ContactRef ct, Group& from, Group& to) 315 { 316 from.relocate_from(ct); 317 to.relocate_to(ct); 318 319 UserRelocatedEvent ev(ct, to, from); 320 contactlist_signal.emit( &ev ); 321 } 322 remove(unsigned int uin)323 void ContactTree::remove(unsigned int uin) 324 { 325 ITERATE_GROUPS_BEGIN 326 if ((*curr).exists(uin)) { 327 (*curr).remove(uin); 328 break; 329 } 330 ITERATE_GROUPS_END 331 } 332 size() const333 unsigned int ContactTree::size() const 334 { 335 unsigned int ret = 0; 336 CONST_ITERATE_GROUPS_BEGIN 337 ret += (*curr).size(); 338 CONST_ITERATE_GROUPS_END 339 return ret; 340 } 341 group_size() const342 unsigned int ContactTree::group_size() const 343 { 344 return m_groups.size(); 345 } 346 empty() const347 bool ContactTree::empty() const 348 { 349 return m_groups.empty(); 350 } 351 exists(unsigned int uin)352 bool ContactTree::exists(unsigned int uin) 353 { 354 ITERATE_GROUPS_BEGIN 355 if ((*curr).exists(uin)) return true; 356 ITERATE_GROUPS_END 357 return false; 358 } 359 mobile_exists(const std::string & m)360 bool ContactTree::mobile_exists(const std::string& m) 361 { 362 ITERATE_GROUPS_BEGIN 363 if ((*curr).mobile_exists(m)) return true; 364 ITERATE_GROUPS_END 365 return false; 366 } 367 email_exists(const std::string & em)368 bool ContactTree::email_exists(const std::string& em) 369 { 370 ITERATE_GROUPS_BEGIN 371 if ((*curr).email_exists(em)) return true; 372 ITERATE_GROUPS_END 373 return false; 374 } 375 begin()376 ContactTree::iterator ContactTree::begin() 377 { 378 return m_groups.begin(); 379 } 380 end()381 ContactTree::iterator ContactTree::end() 382 { 383 return m_groups.end(); 384 } 385 begin() const386 ContactTree::const_iterator ContactTree::begin() const 387 { 388 return m_groups.begin(); 389 } 390 end() const391 ContactTree::const_iterator ContactTree::end() const 392 { 393 return m_groups.end(); 394 } 395 get_unique_group_id() const396 unsigned short ContactTree::get_unique_group_id() const 397 { 398 unsigned short ret; 399 while(1) { 400 ret = (unsigned short) rand(); 401 // this is fine for our simple purposes.. 402 403 bool uniq = true; 404 CONST_ITERATE_GROUPS_BEGIN 405 if ((*curr).get_id() == ret) { 406 uniq = false; 407 break; 408 } 409 CONST_ITERATE_GROUPS_END 410 411 if (uniq) break; 412 } 413 414 return ret; 415 } 416 } 417