You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/libkdegames/kgame/kgamepropertyhandler.cpp

408 lines
11 KiB

/*
This file is part of the KDE games library
Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
Copyright (C) 2001 Martin Heni (martin@heni-online.de)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/*
$Id$
*/
#include "kgamepropertyhandler.h"
#include "kgameproperty.h"
#include "kgamemessage.h"
#include <tqmap.h>
#include <tqptrqueue.h>
#include <klocale.h>
#include <typeinfo>
#define KPLAYERHANDLER_LOAD_COOKIE 6239
//---------------------- KGamePropertyHandler -----------------------------------
class KGamePropertyHandlerPrivate
{
public:
KGamePropertyHandlerPrivate()
{
}
TQMap<int, TQString> mNameMap;
TQIntDict<KGamePropertyBase> mIdDict;
int mUniqueId;
int mId;
KGamePropertyBase::PropertyPolicy mDefaultPolicy;
bool mDefaultUserspace;
int mIndirectEmit;
TQPtrQueue<KGamePropertyBase> mSignalQueue;
};
KGamePropertyHandler::KGamePropertyHandler(int id, const TQObject* receiver, const char * sendf, const char *emitf, TQObject* parent) : TQObject(parent)
{
init();
registerHandler(id,receiver,sendf,emitf);
}
KGamePropertyHandler::KGamePropertyHandler(TQObject* parent) : TQObject(parent)
{
init();
}
KGamePropertyHandler::~KGamePropertyHandler()
{
clear();
delete d;
}
void KGamePropertyHandler::init()
{
kdDebug(11001) << k_funcinfo << ": this=" << this << endl;
d = new KGamePropertyHandlerPrivate; // for future use - is BC important to us?
d->mId = 0;
d->mUniqueId=KGamePropertyBase::IdAutomatic;
d->mDefaultPolicy=KGamePropertyBase::PolicyLocal;
d->mDefaultUserspace=true;
d->mIndirectEmit=0;
}
int KGamePropertyHandler::id() const
{
return d->mId;
}
void KGamePropertyHandler::setId(int id)
{
d->mId = id;
}
void KGamePropertyHandler::registerHandler(int id,const TQObject * receiver, const char * sendf, const char *emitf)
{
setId(id);
if (receiver && sendf) {
kdDebug(11001) << "Connecting TQT_SLOT " << sendf << endl;
connect(this, TQT_SIGNAL(signalSendMessage(int, TQDataStream &, bool*)), receiver, sendf);
}
if (receiver && emitf) {
kdDebug(11001) << "Connecting TQT_SLOT " << emitf << endl;
connect(this, TQT_SIGNAL(signalPropertyChanged(KGamePropertyBase *)), receiver, emitf);
}
}
bool KGamePropertyHandler::processMessage(TQDataStream &stream, int id, bool isSender)
{
// kdDebug(11001) << k_funcinfo << ": id=" << id << " mId=" << d->mId << endl;
if (id != d->mId) {
return false; // Is the message meant for us?
}
KGamePropertyBase* p;
int propertyId;
KGameMessage::extractPropertyHeader(stream, propertyId);
// kdDebug(11001) << k_funcinfo << ": Got property " << propertyId << endl;
if (propertyId==KGamePropertyBase::IdCommand) {
int cmd;
KGameMessage::extractPropertyCommand(stream, propertyId, cmd);
//kdDebug(11001) << k_funcinfo << ": Got COMMAND for id= "<<propertyId <<endl;
p = d->mIdDict.find(propertyId);
if (p) {
if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) {
p->command(stream, cmd, isSender);
}
} else {
kdError(11001) << k_funcinfo << ": (cmd): property " << propertyId << " not found" << endl;
}
return true;
}
p = d->mIdDict.find(propertyId);
if (p) {
//kdDebug(11001) << k_funcinfo << ": Loading " << propertyId << endl;
if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) {
p->load(stream);
}
} else {
kdError(11001) << k_funcinfo << ": property " << propertyId << " not found" << endl;
}
return true;
}
bool KGamePropertyHandler::removeProperty(KGamePropertyBase* data)
{
if (!data) {
return false;
}
d->mNameMap.erase(data->id());
return d->mIdDict.remove(data->id());
}
bool KGamePropertyHandler::addProperty(KGamePropertyBase* data, TQString name)
{
//kdDebug(11001) << k_funcinfo << ": " << data->id() << endl;
if (d->mIdDict.find(data->id())) {
// this id already exists
kdError(11001) << " -> cannot add property " << data->id() << endl;
return false;
} else {
d->mIdDict.insert(data->id(), data);
// if here is a check for "is_debug" or so we can add the strings only in debug mode
// and save memory!!
if (!name.isNull()) {
d->mNameMap[data->id()] = name;
//kdDebug(11001) << k_funcinfo << ": nid="<< (data->id()) << " inserted in Map name=" << d->mNameMap[data->id()] <<endl;
//kdDebug(11001) << "Typeid=" << typeid(data).name() << endl;
//kdDebug(11001) << "Typeid call=" << data->typeinfo()->name() << endl;
}
}
return true;
}
TQString KGamePropertyHandler::propertyName(int id) const
{
TQString s;
if (d->mIdDict.find(id)) {
if (d->mNameMap.contains(id)) {
s = i18n("%1 (%2)").arg(d->mNameMap[id]).arg(id);
} else {
s = i18n("Unnamed - ID: %1").arg(id);
}
} else {
// Should _never_ happen
s = i18n("%1 unregistered").arg(id);
}
return s;
}
bool KGamePropertyHandler::load(TQDataStream &stream)
{
// Prevent direct emmiting until all is loaded
lockDirectEmit();
uint count,i;
stream >> count;
kdDebug(11001) << k_funcinfo << ": " << count << " KGameProperty objects " << endl;
for (i = 0; i < count; i++) {
processMessage(stream, id(),false);
}
TQ_INT16 cookie;
stream >> cookie;
if (cookie == KPLAYERHANDLER_LOAD_COOKIE) {
kdDebug(11001) << " KGamePropertyHandler loaded propertly"<<endl;
} else {
kdError(11001) << "KGamePropertyHandler loading error. probably format error"<<endl;
}
// Allow direct emmiting (if no other lock still holds)
unlockDirectEmit();
return true;
}
bool KGamePropertyHandler::save(TQDataStream &stream)
{
kdDebug(11001) << k_funcinfo << ": " << d->mIdDict.count() << " KGameProperty objects " << endl;
stream << (uint)d->mIdDict.count();
TQIntDictIterator<KGamePropertyBase> it(d->mIdDict);
while (it.current()) {
KGamePropertyBase *base=it.current();
if (base) {
KGameMessage::createPropertyHeader(stream, base->id());
base->save(stream);
}
++it;
}
stream << (TQ_INT16)KPLAYERHANDLER_LOAD_COOKIE;
return true;
}
KGamePropertyBase::PropertyPolicy KGamePropertyHandler::policy()
{
// kdDebug(11001) << k_funcinfo << ": " << d->mDefaultPolicy << endl;
return d->mDefaultPolicy;
}
void KGamePropertyHandler::setPolicy(KGamePropertyBase::PropertyPolicy p,bool userspace)
{
// kdDebug(11001) << k_funcinfo << ": " << p << endl;
d->mDefaultPolicy=p;
d->mDefaultUserspace=userspace;
TQIntDictIterator<KGamePropertyBase> it(d->mIdDict);
while (it.current()) {
if (!userspace || it.current()->id()>=KGamePropertyBase::IdUser) {
it.current()->setPolicy((KGamePropertyBase::PropertyPolicy)p);
}
++it;
}
}
void KGamePropertyHandler::unlockProperties()
{
TQIntDictIterator<KGamePropertyBase> it(d->mIdDict);
while (it.current()) {
it.current()->unlock();
++it;
}
}
void KGamePropertyHandler::lockProperties()
{
TQIntDictIterator<KGamePropertyBase> it(d->mIdDict);
while (it.current()) {
it.current()->lock();
++it;
}
}
int KGamePropertyHandler::uniquePropertyId()
{
return d->mUniqueId++;
}
void KGamePropertyHandler::flush()
{
TQIntDictIterator<KGamePropertyBase> it(d->mIdDict);
while (it.current()) {
if (it.current()->isDirty()) {
it.current()->sendProperty();
}
++it;
}
}
/* Fire all property signal changed which are collected in
* the queque
**/
void KGamePropertyHandler::lockDirectEmit()
{
d->mIndirectEmit++;
}
void KGamePropertyHandler::unlockDirectEmit()
{
// If the flag is <=0 we emit the queued signals
d->mIndirectEmit--;
if (d->mIndirectEmit<=0)
{
KGamePropertyBase *prop;
while((prop=d->mSignalQueue.dequeue()) != 0)
{
// kdDebug(11001) << "emmiting signal for " << prop->id() << endl;
emit signalPropertyChanged(prop);
}
}
}
void KGamePropertyHandler::emitSignal(KGamePropertyBase *prop)
{
// If the indirect flag is set (load and network transmit)
// we cannot emit the signals directly as it can happend that
// a sigal causes an access to a property which is e.g. not
// yet loaded or received
if (d->mIndirectEmit>0)
{
// Queque the signal
d->mSignalQueue.enqueue(prop);
}
else
{
// directly emit
emit signalPropertyChanged(prop);
}
}
bool KGamePropertyHandler::sendProperty(TQDataStream &s)
{
bool sent = false;
emit signalSendMessage(id(), s, &sent);
return sent;
}
KGamePropertyBase *KGamePropertyHandler::find(int id)
{
return d->mIdDict.find(id);
}
void KGamePropertyHandler::clear()
{
kdDebug(11001) << k_funcinfo << id() << endl;
TQIntDictIterator<KGamePropertyBase> it(d->mIdDict);
while (it.toFirst()) {
KGamePropertyBase* p = it.toFirst();
p->unregisterData();
if (d->mIdDict.find(p->id())) {
// shouldn't happen - but if mOwner in KGamePropertyBase is NULL
// this might be possible
removeProperty(p);
}
}
}
TQIntDict<KGamePropertyBase>& KGamePropertyHandler::dict() const
{
return d->mIdDict;
}
TQString KGamePropertyHandler::propertyValue(KGamePropertyBase* prop)
{
if (!prop) {
return i18n("NULL pointer");
}
int id = prop->id();
TQString name = propertyName(id);
TQString value;
const type_info* t = prop->typeinfo();
if (*t == typeid(int)) {
value = TQString::number(((KGamePropertyInt*)prop)->value());
} else if (*t == typeid(unsigned int)) {
value = TQString::number(((KGamePropertyUInt *)prop)->value());
} else if (*t == typeid(long int)) {
value = TQString::number(((KGameProperty<long int> *)prop)->value());
} else if (*t == typeid(unsigned long int)) {
value = TQString::number(((KGameProperty<unsigned long int> *)prop)->value());
} else if (*t == typeid(TQString)) {
value = ((KGamePropertyTQString*)prop)->value();
} else if (*t == typeid(TQ_INT8)) {
value = ((KGamePropertyBool*)prop)->value() ? i18n("True") : i18n("False");
} else {
emit signalRequestValue(prop, value);
}
if (value.isNull()) {
value = i18n("Unknown");
}
return value;
}
void KGamePropertyHandler::Debug()
{
kdDebug(11001) << "-----------------------------------------------------------" << endl;
kdDebug(11001) << "KGamePropertyHandler:: Debug this=" << this << endl;
kdDebug(11001) << " Registered properties: (Policy,Lock,Emit,Optimized, Dirty)" << endl;
TQIntDictIterator<KGamePropertyBase> it(d->mIdDict);
while (it.current()) {
KGamePropertyBase *p=it.current();
kdDebug(11001) << " "<< p->id() << ": p=" << p->policy()
<< " l="<<p->isLocked()
<< " e="<<p->isEmittingSignal()
<< " o=" << p->isOptimized()
<< " d="<<p->isDirty()
<< endl;
++it;
}
kdDebug(11001) << "-----------------------------------------------------------" << endl;
}
#include "kgamepropertyhandler.moc"