kgamepropertyhandler.cpp
00001 /* 00002 This file is part of the KDE games library 00003 Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de) 00004 Copyright (C) 2001 Martin Heni (martin@heni-online.de) 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 /* 00021 $Id$ 00022 */ 00023 00024 #include "kgamepropertyhandler.h" 00025 #include "kgameproperty.h" 00026 #include "kgamemessage.h" 00027 00028 #include <tqmap.h> 00029 #include <tqptrqueue.h> 00030 00031 #include <klocale.h> 00032 #include <typeinfo> 00033 00034 #define KPLAYERHANDLER_LOAD_COOKIE 6239 00035 00036 //---------------------- KGamePropertyHandler ----------------------------------- 00037 class KGamePropertyHandlerPrivate 00038 { 00039 public: 00040 KGamePropertyHandlerPrivate() 00041 { 00042 } 00043 00044 TQMap<int, TQString> mNameMap; 00045 TQIntDict<KGamePropertyBase> mIdDict; 00046 int mUniqueId; 00047 int mId; 00048 KGamePropertyBase::PropertyPolicy mDefaultPolicy; 00049 bool mDefaultUserspace; 00050 int mIndirectEmit; 00051 TQPtrQueue<KGamePropertyBase> mSignalQueue; 00052 }; 00053 00054 KGamePropertyHandler::KGamePropertyHandler(int id, const TQObject* receiver, const char * sendf, const char *emitf, TQObject* parent) : TQObject(parent) 00055 { 00056 init(); 00057 registerHandler(id,receiver,sendf,emitf); 00058 } 00059 00060 KGamePropertyHandler::KGamePropertyHandler(TQObject* parent) : TQObject(parent) 00061 { 00062 init(); 00063 } 00064 00065 KGamePropertyHandler::~KGamePropertyHandler() 00066 { 00067 clear(); 00068 delete d; 00069 } 00070 00071 void KGamePropertyHandler::init() 00072 { 00073 kdDebug(11001) << k_funcinfo << ": this=" << this << endl; 00074 d = new KGamePropertyHandlerPrivate; // for future use - is BC important to us? 00075 d->mId = 0; 00076 d->mUniqueId=KGamePropertyBase::IdAutomatic; 00077 d->mDefaultPolicy=KGamePropertyBase::PolicyLocal; 00078 d->mDefaultUserspace=true; 00079 d->mIndirectEmit=0; 00080 } 00081 00082 00083 int KGamePropertyHandler::id() const 00084 { 00085 return d->mId; 00086 } 00087 00088 void KGamePropertyHandler::setId(int id) 00089 { 00090 d->mId = id; 00091 } 00092 00093 void KGamePropertyHandler::registerHandler(int id,const TQObject * receiver, const char * sendf, const char *emitf) 00094 { 00095 setId(id); 00096 if (receiver && sendf) { 00097 kdDebug(11001) << "Connecting TQT_SLOT " << sendf << endl; 00098 connect(this, TQT_SIGNAL(signalSendMessage(int, TQDataStream &, bool*)), receiver, sendf); 00099 } 00100 if (receiver && emitf) { 00101 kdDebug(11001) << "Connecting TQT_SLOT " << emitf << endl; 00102 connect(this, TQT_SIGNAL(signalPropertyChanged(KGamePropertyBase *)), receiver, emitf); 00103 } 00104 } 00105 00106 bool KGamePropertyHandler::processMessage(TQDataStream &stream, int id, bool isSender) 00107 { 00108 // kdDebug(11001) << k_funcinfo << ": id=" << id << " mId=" << d->mId << endl; 00109 if (id != d->mId) { 00110 return false; // Is the message meant for us? 00111 } 00112 KGamePropertyBase* p; 00113 int propertyId; 00114 KGameMessage::extractPropertyHeader(stream, propertyId); 00115 // kdDebug(11001) << k_funcinfo << ": Got property " << propertyId << endl; 00116 if (propertyId==KGamePropertyBase::IdCommand) { 00117 int cmd; 00118 KGameMessage::extractPropertyCommand(stream, propertyId, cmd); 00119 //kdDebug(11001) << k_funcinfo << ": Got COMMAND for id= "<<propertyId <<endl; 00120 p = d->mIdDict.find(propertyId); 00121 if (p) { 00122 if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) { 00123 p->command(stream, cmd, isSender); 00124 } 00125 } else { 00126 kdError(11001) << k_funcinfo << ": (cmd): property " << propertyId << " not found" << endl; 00127 } 00128 return true; 00129 } 00130 p = d->mIdDict.find(propertyId); 00131 if (p) { 00132 //kdDebug(11001) << k_funcinfo << ": Loading " << propertyId << endl; 00133 if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) { 00134 p->load(stream); 00135 } 00136 } else { 00137 kdError(11001) << k_funcinfo << ": property " << propertyId << " not found" << endl; 00138 } 00139 return true; 00140 } 00141 00142 bool KGamePropertyHandler::removeProperty(KGamePropertyBase* data) 00143 { 00144 if (!data) { 00145 return false; 00146 } 00147 d->mNameMap.erase(data->id()); 00148 return d->mIdDict.remove(data->id()); 00149 } 00150 00151 bool KGamePropertyHandler::addProperty(KGamePropertyBase* data, TQString name) 00152 { 00153 //kdDebug(11001) << k_funcinfo << ": " << data->id() << endl; 00154 if (d->mIdDict.find(data->id())) { 00155 // this id already exists 00156 kdError(11001) << " -> cannot add property " << data->id() << endl; 00157 return false; 00158 } else { 00159 d->mIdDict.insert(data->id(), data); 00160 // if here is a check for "is_debug" or so we can add the strings only in debug mode 00161 // and save memory!! 00162 if (!name.isNull()) { 00163 d->mNameMap[data->id()] = name; 00164 //kdDebug(11001) << k_funcinfo << ": nid="<< (data->id()) << " inserted in Map name=" << d->mNameMap[data->id()] <<endl; 00165 //kdDebug(11001) << "Typeid=" << typeid(data).name() << endl; 00166 //kdDebug(11001) << "Typeid call=" << data->typeinfo()->name() << endl; 00167 } 00168 } 00169 return true; 00170 } 00171 00172 TQString KGamePropertyHandler::propertyName(int id) const 00173 { 00174 TQString s; 00175 if (d->mIdDict.find(id)) { 00176 if (d->mNameMap.contains(id)) { 00177 s = i18n("%1 (%2)").arg(d->mNameMap[id]).arg(id); 00178 } else { 00179 s = i18n("Unnamed - ID: %1").arg(id); 00180 } 00181 } else { 00182 // Should _never_ happen 00183 s = i18n("%1 unregistered").arg(id); 00184 } 00185 return s; 00186 } 00187 00188 bool KGamePropertyHandler::load(TQDataStream &stream) 00189 { 00190 // Prevent direct emmiting until all is loaded 00191 lockDirectEmit(); 00192 uint count,i; 00193 stream >> count; 00194 kdDebug(11001) << k_funcinfo << ": " << count << " KGameProperty objects " << endl; 00195 for (i = 0; i < count; i++) { 00196 processMessage(stream, id(),false); 00197 } 00198 TQ_INT16 cookie; 00199 stream >> cookie; 00200 if (cookie == KPLAYERHANDLER_LOAD_COOKIE) { 00201 kdDebug(11001) << " KGamePropertyHandler loaded propertly"<<endl; 00202 } else { 00203 kdError(11001) << "KGamePropertyHandler loading error. probably format error"<<endl; 00204 } 00205 // Allow direct emmiting (if no other lock still holds) 00206 unlockDirectEmit(); 00207 return true; 00208 } 00209 00210 bool KGamePropertyHandler::save(TQDataStream &stream) 00211 { 00212 kdDebug(11001) << k_funcinfo << ": " << d->mIdDict.count() << " KGameProperty objects " << endl; 00213 stream << (uint)d->mIdDict.count(); 00214 TQIntDictIterator<KGamePropertyBase> it(d->mIdDict); 00215 while (it.current()) { 00216 KGamePropertyBase *base=it.current(); 00217 if (base) { 00218 KGameMessage::createPropertyHeader(stream, base->id()); 00219 base->save(stream); 00220 } 00221 ++it; 00222 } 00223 stream << (TQ_INT16)KPLAYERHANDLER_LOAD_COOKIE; 00224 return true; 00225 } 00226 00227 KGamePropertyBase::PropertyPolicy KGamePropertyHandler::policy() 00228 { 00229 // kdDebug(11001) << k_funcinfo << ": " << d->mDefaultPolicy << endl; 00230 return d->mDefaultPolicy; 00231 } 00232 void KGamePropertyHandler::setPolicy(KGamePropertyBase::PropertyPolicy p,bool userspace) 00233 { 00234 // kdDebug(11001) << k_funcinfo << ": " << p << endl; 00235 d->mDefaultPolicy=p; 00236 d->mDefaultUserspace=userspace; 00237 TQIntDictIterator<KGamePropertyBase> it(d->mIdDict); 00238 while (it.current()) { 00239 if (!userspace || it.current()->id()>=KGamePropertyBase::IdUser) { 00240 it.current()->setPolicy((KGamePropertyBase::PropertyPolicy)p); 00241 } 00242 ++it; 00243 } 00244 } 00245 00246 void KGamePropertyHandler::unlockProperties() 00247 { 00248 TQIntDictIterator<KGamePropertyBase> it(d->mIdDict); 00249 while (it.current()) { 00250 it.current()->unlock(); 00251 ++it; 00252 } 00253 } 00254 00255 void KGamePropertyHandler::lockProperties() 00256 { 00257 TQIntDictIterator<KGamePropertyBase> it(d->mIdDict); 00258 while (it.current()) { 00259 it.current()->lock(); 00260 ++it; 00261 } 00262 } 00263 00264 int KGamePropertyHandler::uniquePropertyId() 00265 { 00266 return d->mUniqueId++; 00267 } 00268 00269 void KGamePropertyHandler::flush() 00270 { 00271 TQIntDictIterator<KGamePropertyBase> it(d->mIdDict); 00272 while (it.current()) { 00273 if (it.current()->isDirty()) { 00274 it.current()->sendProperty(); 00275 } 00276 ++it; 00277 } 00278 } 00279 00280 /* Fire all property signal changed which are collected in 00281 * the queque 00282 **/ 00283 void KGamePropertyHandler::lockDirectEmit() 00284 { 00285 d->mIndirectEmit++; 00286 } 00287 00288 void KGamePropertyHandler::unlockDirectEmit() 00289 { 00290 // If the flag is <=0 we emit the queued signals 00291 d->mIndirectEmit--; 00292 if (d->mIndirectEmit<=0) 00293 { 00294 KGamePropertyBase *prop; 00295 while((prop=d->mSignalQueue.dequeue()) != 0) 00296 { 00297 // kdDebug(11001) << "emmiting signal for " << prop->id() << endl; 00298 emit signalPropertyChanged(prop); 00299 } 00300 } 00301 } 00302 00303 void KGamePropertyHandler::emitSignal(KGamePropertyBase *prop) 00304 { 00305 // If the indirect flag is set (load and network transmit) 00306 // we cannot emit the signals directly as it can happend that 00307 // a sigal causes an access to a property which is e.g. not 00308 // yet loaded or received 00309 00310 if (d->mIndirectEmit>0) 00311 { 00312 // Queque the signal 00313 d->mSignalQueue.enqueue(prop); 00314 } 00315 else 00316 { 00317 // directly emit 00318 emit signalPropertyChanged(prop); 00319 } 00320 } 00321 00322 bool KGamePropertyHandler::sendProperty(TQDataStream &s) 00323 { 00324 bool sent = false; 00325 emit signalSendMessage(id(), s, &sent); 00326 return sent; 00327 } 00328 00329 KGamePropertyBase *KGamePropertyHandler::find(int id) 00330 { 00331 return d->mIdDict.find(id); 00332 } 00333 00334 void KGamePropertyHandler::clear() 00335 { 00336 kdDebug(11001) << k_funcinfo << id() << endl; 00337 TQIntDictIterator<KGamePropertyBase> it(d->mIdDict); 00338 while (it.toFirst()) { 00339 KGamePropertyBase* p = it.toFirst(); 00340 p->unregisterData(); 00341 if (d->mIdDict.find(p->id())) { 00342 // shouldn't happen - but if mOwner in KGamePropertyBase is NULL 00343 // this might be possible 00344 removeProperty(p); 00345 } 00346 } 00347 } 00348 00349 TQIntDict<KGamePropertyBase>& KGamePropertyHandler::dict() const 00350 { 00351 return d->mIdDict; 00352 } 00353 00354 TQString KGamePropertyHandler::propertyValue(KGamePropertyBase* prop) 00355 { 00356 if (!prop) { 00357 return i18n("NULL pointer"); 00358 } 00359 00360 int id = prop->id(); 00361 TQString name = propertyName(id); 00362 TQString value; 00363 00364 const type_info* t = prop->typeinfo(); 00365 if (*t == typeid(int)) { 00366 value = TQString::number(((KGamePropertyInt*)prop)->value()); 00367 } else if (*t == typeid(unsigned int)) { 00368 value = TQString::number(((KGamePropertyUInt *)prop)->value()); 00369 } else if (*t == typeid(long int)) { 00370 value = TQString::number(((KGameProperty<long int> *)prop)->value()); 00371 } else if (*t == typeid(unsigned long int)) { 00372 value = TQString::number(((KGameProperty<unsigned long int> *)prop)->value()); 00373 } else if (*t == typeid(TQString)) { 00374 value = ((KGamePropertyTQString*)prop)->value(); 00375 } else if (*t == typeid(TQ_INT8)) { 00376 value = ((KGamePropertyBool*)prop)->value() ? i18n("True") : i18n("False"); 00377 } else { 00378 emit signalRequestValue(prop, value); 00379 } 00380 00381 if (value.isNull()) { 00382 value = i18n("Unknown"); 00383 } 00384 return value; 00385 } 00386 00387 void KGamePropertyHandler::Debug() 00388 { 00389 kdDebug(11001) << "-----------------------------------------------------------" << endl; 00390 kdDebug(11001) << "KGamePropertyHandler:: Debug this=" << this << endl; 00391 00392 kdDebug(11001) << " Registered properties: (Policy,Lock,Emit,Optimized, Dirty)" << endl; 00393 TQIntDictIterator<KGamePropertyBase> it(d->mIdDict); 00394 while (it.current()) { 00395 KGamePropertyBase *p=it.current(); 00396 kdDebug(11001) << " "<< p->id() << ": p=" << p->policy() 00397 << " l="<<p->isLocked() 00398 << " e="<<p->isEmittingSignal() 00399 << " o=" << p->isOptimized() 00400 << " d="<<p->isDirty() 00401 << endl; 00402 ++it; 00403 } 00404 kdDebug(11001) << "-----------------------------------------------------------" << endl; 00405 } 00406 00407 #include "kgamepropertyhandler.moc"