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: kgamepropertyhandler.cpp 465369 2005-09-29 14:33:08Z mueller $
00022 */
00023 
00024 #include "kgamepropertyhandler.h"
00025 #include "kgameproperty.h"
00026 #include "kgamemessage.h"
00027 
00028 #include <qmap.h>
00029 #include <qptrqueue.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     QMap<int, QString> mNameMap;
00045     QIntDict<KGamePropertyBase> mIdDict;
00046     int mUniqueId;
00047     int mId;
00048     KGamePropertyBase::PropertyPolicy mDefaultPolicy;
00049     bool mDefaultUserspace;
00050   int mIndirectEmit;
00051   QPtrQueue<KGamePropertyBase> mSignalQueue;
00052 };
00053 
00054 KGamePropertyHandler::KGamePropertyHandler(int id, const QObject* receiver, const char * sendf, const char *emitf, QObject* parent) : QObject(parent)
00055 {
00056  init();
00057  registerHandler(id,receiver,sendf,emitf);
00058 }
00059 
00060 KGamePropertyHandler::KGamePropertyHandler(QObject* parent) : QObject(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 QObject * receiver, const char * sendf, const char *emitf)
00094 {
00095  setId(id); 
00096  if (receiver && sendf) {
00097     kdDebug(11001) << "Connecting SLOT " << sendf << endl;
00098     connect(this, SIGNAL(signalSendMessage(int, QDataStream &, bool*)), receiver, sendf);
00099  }
00100  if (receiver && emitf) {
00101     kdDebug(11001) << "Connecting SLOT " << emitf << endl;
00102     connect(this, SIGNAL(signalPropertyChanged(KGamePropertyBase *)), receiver, emitf);
00103  }
00104 }
00105 
00106 bool KGamePropertyHandler::processMessage(QDataStream &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, QString 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 QString KGamePropertyHandler::propertyName(int id) const
00173 {
00174  QString 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(QDataStream &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  Q_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(QDataStream &stream)
00211 {
00212  kdDebug(11001) << k_funcinfo << ": " << d->mIdDict.count() << " KGameProperty objects " << endl;
00213  stream << (uint)d->mIdDict.count();
00214  QIntDictIterator<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 << (Q_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  QIntDictIterator<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  QIntDictIterator<KGamePropertyBase> it(d->mIdDict);
00249  while (it.current()) {
00250     it.current()->unlock();
00251     ++it;
00252  }
00253 }
00254 
00255 void KGamePropertyHandler::lockProperties()
00256 {
00257  QIntDictIterator<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  QIntDictIterator<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(QDataStream &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  QIntDictIterator<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 QIntDict<KGamePropertyBase>& KGamePropertyHandler::dict() const
00350 { 
00351  return d->mIdDict; 
00352 }
00353 
00354 QString KGamePropertyHandler::propertyValue(KGamePropertyBase* prop)
00355 {
00356  if (!prop) {
00357          return i18n("NULL pointer");
00358  }
00359        
00360  int id = prop->id();
00361  QString name = propertyName(id);
00362  QString value;
00363 
00364  const type_info* t = prop->typeinfo();
00365  if (*t == typeid(int)) {
00366     value = QString::number(((KGamePropertyInt*)prop)->value());
00367  } else if (*t == typeid(unsigned int)) {
00368     value = QString::number(((KGamePropertyUInt *)prop)->value());
00369  } else if (*t == typeid(long int)) {
00370     value = QString::number(((KGameProperty<long int> *)prop)->value()); 
00371  } else if (*t == typeid(unsigned long int)) {
00372     value = QString::number(((KGameProperty<unsigned long int> *)prop)->value());
00373  } else if (*t == typeid(QString)) { 
00374     value = ((KGamePropertyQString*)prop)->value();
00375  } else if (*t == typeid(Q_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  QIntDictIterator<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"
KDE Home | KDE Accessibility Home | Description of Access Keys