KDEGames

kgamepropertyhandler.cpp
1 /*
2  This file is part of the KDE games library
3  SPDX-FileCopyrightText: 2001 Andreas Beckermann <[email protected]>
4  SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #include "kgamepropertyhandler.h"
10 
11 // own
12 #include "kgamemessage.h"
13 // KF
14 #include <KLocalizedString>
15 // Qt
16 #include <QMap>
17 #include <QQueue>
18 
19 #define KPLAYERHANDLER_LOAD_COOKIE 6239
20 
21 //---------------------- KGamePropertyHandler -----------------------------------
22 class KGamePropertyHandlerPrivate
23 {
24 public:
25  KGamePropertyHandlerPrivate(KGamePropertyHandler *qq)
26  : q(qq), mUniqueId(KGamePropertyBase::IdAutomatic), mId(0),
27  mDefaultPolicy(KGamePropertyBase::PolicyLocal), mDefaultUserspace(true),
28  mIndirectEmit(0)
29  {
30  //qDebug() << ": this=" << q;
31  }
32 
34  QMap<int, QString> mNameMap;
36  int mUniqueId;
37  int mId;
38  KGamePropertyBase::PropertyPolicy mDefaultPolicy;
39  bool mDefaultUserspace;
40  int mIndirectEmit;
41  QQueue<KGamePropertyBase*> mSignalQueue;
42 };
43 
44 KGamePropertyHandler::KGamePropertyHandler(int id, const QObject* receiver, const char * sendf, const char *emitf, QObject* parent)
45  : QObject(parent), d(new KGamePropertyHandlerPrivate(this))
46 {
47  registerHandler(id,receiver,sendf,emitf);
48 }
49 
51  : QObject(parent), d(new KGamePropertyHandlerPrivate(this))
52 {
53 }
54 
55 KGamePropertyHandler::~KGamePropertyHandler()
56 {
57  //qDebug() ;
58  clear();
59  //qDebug() << "done";
60 }
61 
63 {
64  return d->mId;
65 }
66 
68 {
69  d->mId = id;
70 }
71 
72 void KGamePropertyHandler::registerHandler(int id,const QObject * receiver, const char * sendf, const char *emitf)
73 {
74  setId(id);
75  if (receiver && sendf) {
76  connect(this, SIGNAL(signalSendMessage(int,QDataStream&,bool*)), receiver, sendf);
77  }
78  if (receiver && emitf) {
79  connect(this, SIGNAL(signalPropertyChanged(KGamePropertyBase*)), receiver, emitf);
80  }
81 }
82 
83 bool KGamePropertyHandler::processMessage(QDataStream &stream, int id, bool isSender)
84 {
85 // qDebug() << ": id=" << id << "mId=" << d->mId;
86  if (id != d->mId) {
87  return false; // Is the message meant for us?
88  }
90  int propertyId;
91  KGameMessage::extractPropertyHeader(stream, propertyId);
92 // qDebug() << ": Got property" << propertyId;
93  if (propertyId==KGamePropertyBase::IdCommand) {
94  int cmd;
95  KGameMessage::extractPropertyCommand(stream, propertyId, cmd);
96 //qDebug() << ": Got COMMAND for id= "<<propertyId;
97  QMultiHash<int, KGamePropertyBase*>::iterator it = d->mIdDict.find(propertyId);
98  if (it != d->mIdDict.end()) {
99  p = *it;
100  if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) {
101  p->command(stream, cmd, isSender);
102  }
103  } else {
104  qCritical() << ": (cmd): property" << propertyId << "not found";
105  }
106  return true;
107  }
108  QMultiHash<int, KGamePropertyBase*>::iterator it = d->mIdDict.find(propertyId);
109  if (it != d->mIdDict.end()) {
110  p = *it;
111  //qDebug() << ": Loading" << propertyId;
112  if (!isSender || p->policy()==KGamePropertyBase::PolicyClean) {
113  p->load(stream);
114  }
115  } else {
116  qCritical() << ": property" << propertyId << "not found";
117  }
118  return true;
119 }
120 
122 {
123  if (!data) {
124  return false;
125  }
126 
127  d->mNameMap.remove(data->id());
128  return d->mIdDict.remove(data->id());
129 }
130 
132 {
133  //qDebug() << ":" << data->id();
134  if ( d->mIdDict.find(data->id()) != d->mIdDict.end() ) {
135  // this id already exists
136  qCritical() << " -> cannot add property" << data->id();
137  return false;
138  } else {
139  d->mIdDict.insert(data->id(), data);
140  // if here is a check for "is_debug" or so we can add the strings only in debug mode
141  // and save memory!!
142  if (!name.isNull()) {
143  d->mNameMap[data->id()] = name;
144  //qDebug() << ": nid="<< (data->id()) << "inserted in Map name=" << d->mNameMap[data->id()];
145  //qDebug() << "Typeid=" << typeid(data).name();
146  //qDebug() << "Typeid call=" << data->typeinfo()->name();
147  }
148  }
149  return true;
150 }
151 
153 {
154  QString s;
155  if (d->mIdDict.find(id) != d->mIdDict.end()) {
156  if (d->mNameMap.contains(id)) {
157  s = i18n("%1 (%2)", d->mNameMap[id], id);
158  } else {
159  s = i18n("Unnamed - ID: %1", id);
160  }
161  } else {
162  // Should _never_ happen
163  s = i18np("%1 unregistered", "%1 unregistered", id);
164  }
165  return s;
166 }
167 
169 {
170  // Prevent direct emitting until all is loaded
171  lockDirectEmit();
172  uint count,i;
173  stream >> count;
174  qDebug() << ":" << count << "KGameProperty objects";
175  for (i = 0; i < count; ++i) {
176  processMessage(stream, id(),false);
177  }
178  qint16 cookie;
179  stream >> cookie;
180  if (cookie == KPLAYERHANDLER_LOAD_COOKIE) {
181  qDebug() << " KGamePropertyHandler loaded properly";
182  } else {
183  qCritical() << "KGamePropertyHandler loading error. probably format error";
184  }
185  // Allow direct emitting (if no other lock still holds)
187  return true;
188 }
189 
191 {
192  qDebug() << ":" << d->mIdDict.count() << "KGameProperty objects";
193  stream << (uint)d->mIdDict.count();
195  while (it.hasNext()) {
196 it.next();
197  KGamePropertyBase *base=it.value();
198  if (base) {
199  KGameMessage::createPropertyHeader(stream, base->id());
200  base->save(stream);
201  }
202  }
203  stream << (qint16)KPLAYERHANDLER_LOAD_COOKIE;
204  return true;
205 }
206 
208 {
209 // qDebug() << ":" << d->mDefaultPolicy;
210  return d->mDefaultPolicy;
211 }
213 {
214  // qDebug() << ":" << p;
215  d->mDefaultPolicy=p;
216  d->mDefaultUserspace=userspace;
218  while (it.hasNext()) {
219 it.next();
220  if (!userspace || it.value()->id()>=KGamePropertyBase::IdUser) {
221  it.value()->setPolicy((KGamePropertyBase::PropertyPolicy)p);
222  }
223  }
224 }
225 
227 {
229  while (it.hasNext()) {
230 it.next();
231  it.value()->unlock();
232  }
233 }
234 
236 {
238  while (it.hasNext()) {
239 it.next();
240  it.value()->lock();
241  }
242 }
243 
245 {
246  return d->mUniqueId++;
247 }
248 
250 {
252  while (it.hasNext()) {
253 it.next();
254  if (it.value()->isDirty()) {
255  it.value()->sendProperty();
256  }
257  }
258 }
259 
260 /* Fire all property signal changed which are collected in
261  * the queque
262  **/
264 {
265  d->mIndirectEmit++;
266 }
267 
269 {
270  // If the flag is <=0 we emit the queued signals
271  d->mIndirectEmit--;
272  if (d->mIndirectEmit<=0)
273  {
274  while(!d->mSignalQueue.isEmpty())
275  {
276  KGamePropertyBase *prop=d->mSignalQueue.dequeue();
277 // qDebug() << "emitting signal for" << prop->id();
279  }
280  }
281 }
282 
284 {
285  // If the indirect flag is set (load and network transmit)
286  // we cannot emit the signals directly as it can happened that
287  // a signal causes an access to a property which is e.g. not
288  // yet loaded or received
289 
290  if (d->mIndirectEmit>0)
291  {
292  // Queque the signal
293  d->mSignalQueue.enqueue(prop);
294  }
295  else
296  {
297  // directly emit
299  }
300 }
301 
303 {
304  bool sent = false;
305  Q_EMIT signalSendMessage(id(), s, &sent);
306  return sent;
307 }
308 
310 {
311  if (d->mIdDict.find(id) == d->mIdDict.end())
312  return nullptr;
313  return *(d->mIdDict.find(id));
314 }
315 
317 {
318  // Note: Hash iterator method 'toFront()' crashes when applied to first item.
319  // Therefore we get the keys as list first.
320  QList<int> list = d->mIdDict.keys();
321  for (int i = 0; i < list.size(); ++i)
322  {
323  int key = list.at(i);
324  KGamePropertyBase* p = d->mIdDict.value(key);
325  p->unregisterData();
326  if (d->mIdDict.find(p->id()) != d->mIdDict.end())
327  {
328  // shouldn't happen - but if mOwner in KGamePropertyBase is NULL
329  // this might be possible
330  removeProperty(p);
331  }
332  }
333 }
334 
336 {
337  return d->mIdDict;
338 }
339 
341 {
342  if (!prop) {
343  return i18n("NULL pointer");
344  }
345 
346  QString value;
347 
348  const type_info* t = prop->typeinfo();
349  if (*t == typeid(int)) {
350  value = QString::number(((KGamePropertyInt*)prop)->value());
351  } else if (*t == typeid(unsigned int)) {
352  value = QString::number(((KGamePropertyUInt *)prop)->value());
353  } else if (*t == typeid(long int)) {
354  value = QString::number(((KGameProperty<qint64> *)prop)->value());
355  } else if (*t == typeid(unsigned long int)) {
356  value = QString::number(((KGameProperty<quint64> *)prop)->value());
357  } else if (*t == typeid(QString)) {
358  value = ((KGamePropertyQString*)prop)->value();
359  } else if (*t == typeid(qint8)) {
360  value = ((KGamePropertyBool*)prop)->value() ? i18n("True") : i18n("False");
361  } else {
362  Q_EMIT signalRequestValue(prop, value);
363  }
364 
365  if (value.isNull()) {
366  value = i18n("Unknown");
367  }
368  return value;
369 }
370 
372 {
373  qDebug() << "-----------------------------------------------------------";
374  qDebug() << "KGamePropertyHandler:: Debug this=" << this;
375 
376  qDebug() << " Registered properties: (Policy,Lock,Emit,Optimized, Dirty)";
378  while (it.hasNext()) {
379 it.next();
380  KGamePropertyBase *p=it.value();
381  qDebug() << " "<< p->id() << ": p=" << p->policy()
382  << "l="<<p->isLocked()
383  << "e="<<p->isEmittingSignal()
384  << "o=" << p->isOptimized()
385  << "d="<<p->isDirty();
386  }
387  qDebug() << "-----------------------------------------------------------";
388 }
389 
390 
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:35
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-2021 The KDE developers.
Generated on Tue Dec 7 2021 22:34:14 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.