KDEGames

kgamepropertyhandler.cpp
1 /*
2  This file is part of the KDE games library
3  Copyright (C) 2001 Andreas Beckermann ([email protected])
4  Copyright (C) 2001 Martin Heni (kde at heni-online.de)
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2 as published by the Free Software Foundation.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "kgamepropertyhandler.h"
22 #include "kgamemessage.h"
23 
24 #include <QMap>
25 #include <QQueue>
26 
27 #include <KLocalizedString>
28 
29 #define KPLAYERHANDLER_LOAD_COOKIE 6239
30 
31 //---------------------- KGamePropertyHandler -----------------------------------
32 class KGamePropertyHandlerPrivate
33 {
34 public:
35  KGamePropertyHandlerPrivate(KGamePropertyHandler *qq)
36  : q(qq), mUniqueId(KGamePropertyBase::IdAutomatic), mId(0),
37  mDefaultPolicy(KGamePropertyBase::PolicyLocal), mDefaultUserspace(true),
38  mIndirectEmit(0)
39  {
40  //qDebug() << ": this=" << q;
41  }
42 
44  QMap<int, QString> mNameMap;
46  int mUniqueId;
47  int mId;
48  KGamePropertyBase::PropertyPolicy mDefaultPolicy;
49  bool mDefaultUserspace;
50  int mIndirectEmit;
51  QQueue<KGamePropertyBase*> mSignalQueue;
52 };
53 
54 KGamePropertyHandler::KGamePropertyHandler(int id, const QObject* receiver, const char * sendf, const char *emitf, QObject* parent)
55  : QObject(parent), d(new KGamePropertyHandlerPrivate(this))
56 {
57  registerHandler(id,receiver,sendf,emitf);
58 }
59 
61  : QObject(parent), d(new KGamePropertyHandlerPrivate(this))
62 {
63 }
64 
65 KGamePropertyHandler::~KGamePropertyHandler()
66 {
67  //qDebug() ;
68  clear();
69  delete d;
70  //qDebug() << "done";
71 }
72 
74 {
75  return d->mId;
76 }
77 
79 {
80  d->mId = id;
81 }
82 
83 void KGamePropertyHandler::registerHandler(int id,const QObject * receiver, const char * sendf, const char *emitf)
84 {
85  setId(id);
86  if (receiver && sendf) {
87  connect(this, SIGNAL(signalSendMessage(int,QDataStream&,bool*)), receiver, sendf);
88  }
89  if (receiver && emitf) {
90  connect(this, SIGNAL(signalPropertyChanged(KGamePropertyBase*)), receiver, emitf);
91  }
92 }
93 
94 bool KGamePropertyHandler::processMessage(QDataStream &stream, int id, bool isSender)
95 {
96 // qDebug() << ": id=" << id << "mId=" << d->mId;
97  if (id != d->mId) {
98  return false; // Is the message meant for us?
99  }
101  int propertyId;
102  KGameMessage::extractPropertyHeader(stream, propertyId);
103 // qDebug() << ": Got property" << propertyId;
104  if (propertyId==KGamePropertyBase::IdCommand) {
105  int cmd;
106  KGameMessage::extractPropertyCommand(stream, propertyId, cmd);
107 //qDebug() << ": Got COMMAND for id= "<<propertyId;
108  QMultiHash<int, KGamePropertyBase*>::iterator it = d->mIdDict.find(propertyId);
109  if (it != d->mIdDict.end()) {
110  p = *it;
111  if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) {
112  p->command(stream, cmd, isSender);
113  }
114  } else {
115  qCritical() << ": (cmd): property" << propertyId << "not found";
116  }
117  return true;
118  }
119  QMultiHash<int, KGamePropertyBase*>::iterator it = d->mIdDict.find(propertyId);
120  if (it != d->mIdDict.end()) {
121  p = *it;
122  //qDebug() << ": Loading" << propertyId;
123  if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) {
124  p->load(stream);
125  }
126  } else {
127  qCritical() << ": property" << propertyId << "not found";
128  }
129  return true;
130 }
131 
133 {
134  if (!data) {
135  return false;
136  }
137 
138  d->mNameMap.remove(data->id());
139  return d->mIdDict.remove(data->id());
140 }
141 
143 {
144  //qDebug() << ":" << data->id();
145  if ( d->mIdDict.find(data->id()) != d->mIdDict.end() ) {
146  // this id already exists
147  qCritical() << " -> cannot add property" << data->id();
148  return false;
149  } else {
150  d->mIdDict.insert(data->id(), data);
151  // if here is a check for "is_debug" or so we can add the strings only in debug mode
152  // and save memory!!
153  if (!name.isNull()) {
154  d->mNameMap[data->id()] = name;
155  //qDebug() << ": nid="<< (data->id()) << "inserted in Map name=" << d->mNameMap[data->id()];
156  //qDebug() << "Typeid=" << typeid(data).name();
157  //qDebug() << "Typeid call=" << data->typeinfo()->name();
158  }
159  }
160  return true;
161 }
162 
164 {
165  QString s;
166  if (d->mIdDict.find(id) != d->mIdDict.end()) {
167  if (d->mNameMap.contains(id)) {
168  s = i18n("%1 (%2)", d->mNameMap[id], id);
169  } else {
170  s = i18n("Unnamed - ID: %1", id);
171  }
172  } else {
173  // Should _never_ happen
174  s = i18np("%1 unregistered", "%1 unregistered", id);
175  }
176  return s;
177 }
178 
180 {
181  // Prevent direct emitting until all is loaded
182  lockDirectEmit();
183  uint count,i;
184  stream >> count;
185  qDebug() << ":" << count << "KGameProperty objects";
186  for (i = 0; i < count; ++i) {
187  processMessage(stream, id(),false);
188  }
189  qint16 cookie;
190  stream >> cookie;
191  if (cookie == KPLAYERHANDLER_LOAD_COOKIE) {
192  qDebug() << " KGamePropertyHandler loaded properly";
193  } else {
194  qCritical() << "KGamePropertyHandler loading error. probably format error";
195  }
196  // Allow direct emitting (if no other lock still holds)
198  return true;
199 }
200 
202 {
203  qDebug() << ":" << d->mIdDict.count() << "KGameProperty objects";
204  stream << (uint)d->mIdDict.count();
206  while (it.hasNext()) {
207 it.next();
208  KGamePropertyBase *base=it.value();
209  if (base) {
210  KGameMessage::createPropertyHeader(stream, base->id());
211  base->save(stream);
212  }
213  }
214  stream << (qint16)KPLAYERHANDLER_LOAD_COOKIE;
215  return true;
216 }
217 
219 {
220 // qDebug() << ":" << d->mDefaultPolicy;
221  return d->mDefaultPolicy;
222 }
224 {
225  // qDebug() << ":" << p;
226  d->mDefaultPolicy=p;
227  d->mDefaultUserspace=userspace;
229  while (it.hasNext()) {
230 it.next();
231  if (!userspace || it.value()->id()>=KGamePropertyBase::IdUser) {
232  it.value()->setPolicy((KGamePropertyBase::PropertyPolicy)p);
233  }
234  }
235 }
236 
238 {
240  while (it.hasNext()) {
241 it.next();
242  it.value()->unlock();
243  }
244 }
245 
247 {
249  while (it.hasNext()) {
250 it.next();
251  it.value()->lock();
252  }
253 }
254 
256 {
257  return d->mUniqueId++;
258 }
259 
261 {
263  while (it.hasNext()) {
264 it.next();
265  if (it.value()->isDirty()) {
266  it.value()->sendProperty();
267  }
268  }
269 }
270 
271 /* Fire all property signal changed which are collected in
272  * the queque
273  **/
275 {
276  d->mIndirectEmit++;
277 }
278 
280 {
281  // If the flag is <=0 we emit the queued signals
282  d->mIndirectEmit--;
283  if (d->mIndirectEmit<=0)
284  {
285  while(!d->mSignalQueue.isEmpty())
286  {
287  KGamePropertyBase *prop=d->mSignalQueue.dequeue();
288 // qDebug() << "emitting signal for" << prop->id();
290  }
291  }
292 }
293 
295 {
296  // If the indirect flag is set (load and network transmit)
297  // we cannot emit the signals directly as it can happened that
298  // a signal causes an access to a property which is e.g. not
299  // yet loaded or received
300 
301  if (d->mIndirectEmit>0)
302  {
303  // Queque the signal
304  d->mSignalQueue.enqueue(prop);
305  }
306  else
307  {
308  // directly emit
310  }
311 }
312 
314 {
315  bool sent = false;
316  Q_EMIT signalSendMessage(id(), s, &sent);
317  return sent;
318 }
319 
321 {
322  if (d->mIdDict.find(id) == d->mIdDict.end())
323  return nullptr;
324  return *(d->mIdDict.find(id));
325 }
326 
328 {
329  // Note: Hash iterator method 'toFront()' crashes when applied to first item.
330  // Therefore we get the keys as list first.
331  QList<int> list = d->mIdDict.keys();
332  for (int i = 0; i < list.size(); ++i)
333  {
334  int key = list.at(i);
335  KGamePropertyBase* p = d->mIdDict.value(key);
336  p->unregisterData();
337  if (d->mIdDict.find(p->id()) != d->mIdDict.end())
338  {
339  // shouldn't happen - but if mOwner in KGamePropertyBase is NULL
340  // this might be possible
341  removeProperty(p);
342  }
343  }
344 }
345 
347 {
348  return d->mIdDict;
349 }
350 
352 {
353  if (!prop) {
354  return i18n("NULL pointer");
355  }
356 
357  int id = prop->id();
358  QString name = propertyName(id);
359  QString value;
360 
361  const type_info* t = prop->typeinfo();
362  if (*t == typeid(int)) {
363  value = QString::number(((KGamePropertyInt*)prop)->value());
364  } else if (*t == typeid(unsigned int)) {
365  value = QString::number(((KGamePropertyUInt *)prop)->value());
366  } else if (*t == typeid(long int)) {
367  value = QString::number(((KGameProperty<qint64> *)prop)->value());
368  } else if (*t == typeid(unsigned long int)) {
369  value = QString::number(((KGameProperty<quint64> *)prop)->value());
370  } else if (*t == typeid(QString)) {
371  value = ((KGamePropertyQString*)prop)->value();
372  } else if (*t == typeid(qint8)) {
373  value = ((KGamePropertyBool*)prop)->value() ? i18n("True") : i18n("False");
374  } else {
375  Q_EMIT signalRequestValue(prop, value);
376  }
377 
378  if (value.isNull()) {
379  value = i18n("Unknown");
380  }
381  return value;
382 }
383 
385 {
386  qDebug() << "-----------------------------------------------------------";
387  qDebug() << "KGamePropertyHandler:: Debug this=" << this;
388 
389  qDebug() << " Registered properties: (Policy,Lock,Emit,Optimized, Dirty)";
391  while (it.hasNext()) {
392 it.next();
393  KGamePropertyBase *p=it.value();
394  qDebug() << " "<< p->id() << ": p=" << p->policy()
395  << "l="<<p->isLocked()
396  << "e="<<p->isEmittingSignal()
397  << "o=" << p->isOptimized()
398  << "d="<<p->isDirty();
399  }
400  qDebug() << "-----------------------------------------------------------";
401 }
402 
403 
QString propertyName(int id) const
void lockDirectEmit()
Called by the KGame or KPlayer object or the handler itself to delay emitting of signals.
void setId(int id)
Use id as new ID for this KGamePropertyHandler.
bool isLocked() const
A locked property can only be changed by the player who has set the lock.
A collection class for KGameProperty objects.
void flush()
Sends all properties which are marked dirty over the network.
bool hasNext() const const
bool removeProperty(KGamePropertyBase *data)
Removes a property from the handler.
const T & at(int i) const const
PropertyPolicy
The policy of the property.
void clear()
Clear the KGamePropertyHandler.
void signalRequestValue(KGamePropertyBase *property, QString &value)
If you call propertyValue with a non-standard KGameProperty it is possible that the value cannot auto...
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
virtual bool load(QDataStream &stream)
Loads properties from the datastream.
void registerHandler(int id, const QObject *receiver, const char *send, const char *emit)
Register the handler with a parent.
int size() const const
bool isNull() const const
void Debug()
Writes some debug output to the console.
QString number(int n, int base)
virtual bool save(QDataStream &stream)
Saves properties into the datastream.
KGamePropertyBase * find(int id)
void emitSignal(KGamePropertyBase *data)
called by a property to emit a signal This call is simply forwarded to the parent object ...
bool isDirty() const
void lockProperties()
Calls KGamePropertyBase::setReadOnly(true) for all properties of this handler.
virtual const type_info * typeinfo()
KGamePropertyHandler(QObject *parent=nullptr)
Construct an unregistered KGamePropertyHandler.
int uniquePropertyId()
returns a unique property ID starting called usually with a base of KGamePropertyBase::IdAutomatic.
void signalPropertyChanged(KGamePropertyBase *)
This is emitted by a property.
void setPolicy(KGamePropertyBase::PropertyPolicy p, bool userspace=true)
Set the policy for all kgame variables which are currently registered in the KGame property handler...
bool isOptimized() const
See also setOptimize.
bool sendProperty(QDataStream &s)
called by a property to send itself into the datastream.
void signalSendMessage(int msgid, QDataStream &, bool *sent)
This signal is emitted when a property needs to be sent.
QString propertyValue(KGamePropertyBase *property)
In several situations you just want to have a QString of a KGameProperty object.
QMultiHash< int, KGamePropertyBase * > & dict() const
Reference to the internal dictionary.
Base class of KGameProperty.
Definition: kgameproperty.h:45
QHashIterator::Item next()
virtual void load(QDataStream &s)=0
This will read the value of this property from the stream.
QString i18n(const char *text, const TYPE &arg...)
virtual void save(QDataStream &s)=0
Write the value into a stream.
bool addProperty(KGamePropertyBase *data, const QString &name=QString())
Adds a KGameProperty property to the handler.
PropertyPolicy policy() const
virtual void command(QDataStream &stream, int msgid, bool isSender=false)
send a command to advanced properties like arrays
bool processMessage(QDataStream &stream, int id, bool isSender)
Main message process function.
const T & value() const const
void unlockProperties()
Calls KGamePropertyBase::setReadOnly(false) for all properties of this player.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
KGamePropertyBase::PropertyPolicy policy()
Returns the default policy for this property handler.
void unlockDirectEmit()
Removes the lock from the emitting of property signals.
int id() const
Q_EMITQ_EMIT
bool isEmittingSignal() const
See also setEmittingSignal.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Nov 30 2020 22:37:54 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.