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 #include <kdegamesprivate_logging.h>
14 // KF
15 #include <KLocalizedString>
16 // Qt
17 #include <QMap>
18 #include <QQueue>
19 
20 #define KPLAYERHANDLER_LOAD_COOKIE 6239
21 
22 //---------------------- KGamePropertyHandler -----------------------------------
23 class KGamePropertyHandlerPrivate
24 {
25 public:
26  explicit KGamePropertyHandlerPrivate(KGamePropertyHandler *qq)
27  : q(qq)
28  {
29  // qDebug() << ": this=" << q;
30  }
31 
32 public:
33  KGamePropertyHandler *const q;
34 
35  QMap<int, QString> mNameMap;
37  int mUniqueId = KGamePropertyBase::IdAutomatic;
38  int mId = 0;
39  KGamePropertyBase::PropertyPolicy mDefaultPolicy = KGamePropertyBase::PolicyLocal;
40  bool mDefaultUserspace = true;
41  int mIndirectEmit = 0;
42  QQueue<KGamePropertyBase *> mSignalQueue;
43 };
44 
45 KGamePropertyHandler::KGamePropertyHandler(int id, const QObject *receiver, const char *sendf, const char *emitf, QObject *parent)
46  : QObject(parent)
47  , d(new KGamePropertyHandlerPrivate(this))
48 {
49  registerHandler(id, receiver, sendf, emitf);
50 }
51 
53  : QObject(parent)
54  , d(new KGamePropertyHandlerPrivate(this))
55 {
56 }
57 
58 KGamePropertyHandler::~KGamePropertyHandler()
59 {
60  // qDebug() ;
61  clear();
62  // qDebug() << "done";
63 }
64 
66 {
67  return d->mId;
68 }
69 
71 {
72  d->mId = id;
73 }
74 
75 void KGamePropertyHandler::registerHandler(int id, const QObject *receiver, const char *sendf, const char *emitf)
76 {
77  setId(id);
78  if (receiver && sendf) {
79  connect(this, SIGNAL(signalSendMessage(int, QDataStream &, bool *)), receiver, sendf);
80  }
81  if (receiver && emitf) {
82  connect(this, SIGNAL(signalPropertyChanged(KGamePropertyBase *)), receiver, emitf);
83  }
84 }
85 
86 bool KGamePropertyHandler::processMessage(QDataStream &stream, int id, bool isSender)
87 {
88  // qDebug() << ": id=" << id << "mId=" << d->mId;
89  if (id != d->mId) {
90  return false; // Is the message meant for us?
91  }
93  int propertyId;
94  KGameMessage::extractPropertyHeader(stream, propertyId);
95  // qDebug() << ": Got property" << propertyId;
96  if (propertyId == KGamePropertyBase::IdCommand) {
97  int cmd;
98  KGameMessage::extractPropertyCommand(stream, propertyId, cmd);
99  // qDebug() << ": Got COMMAND for id= "<<propertyId;
100  QMultiHash<int, KGamePropertyBase *>::iterator it = d->mIdDict.find(propertyId);
101  if (it != d->mIdDict.end()) {
102  p = *it;
103  if (!isSender || p->policy() == KGamePropertyBase::PolicyClean) {
104  p->command(stream, cmd, isSender);
105  }
106  } else {
107  qCCritical(KDEGAMESPRIVATE_LOG) << ": (cmd): property" << propertyId << "not found";
108  }
109  return true;
110  }
111  QMultiHash<int, KGamePropertyBase *>::iterator it = d->mIdDict.find(propertyId);
112  if (it != d->mIdDict.end()) {
113  p = *it;
114  // qDebug() << ": Loading" << propertyId;
115  if (!isSender || p->policy() == KGamePropertyBase::PolicyClean) {
116  p->load(stream);
117  }
118  } else {
119  qCCritical(KDEGAMESPRIVATE_LOG) << ": property" << propertyId << "not found";
120  }
121  return true;
122 }
123 
125 {
126  if (!data) {
127  return false;
128  }
129 
130  d->mNameMap.remove(data->id());
131  return d->mIdDict.remove(data->id());
132 }
133 
135 {
136  // qDebug() << ":" << data->id();
137  if (d->mIdDict.find(data->id()) != d->mIdDict.end()) {
138  // this id already exists
139  qCCritical(KDEGAMESPRIVATE_LOG) << " -> cannot add property" << data->id();
140  return false;
141  } else {
142  d->mIdDict.insert(data->id(), data);
143  // if here is a check for "is_debug" or so we can add the strings only in debug mode
144  // and save memory!!
145  if (!name.isEmpty()) {
146  d->mNameMap[data->id()] = name;
147  // qDebug() << ": nid="<< (data->id()) << "inserted in Map name=" << d->mNameMap[data->id()];
148  // qDebug() << "Typeid=" << typeid(data).name();
149  // qDebug() << "Typeid call=" << data->typeinfo()->name();
150  }
151  }
152  return true;
153 }
154 
156 {
157  QString s;
158  if (d->mIdDict.find(id) != d->mIdDict.end()) {
159  if (d->mNameMap.contains(id)) {
160  s = i18n("%1 (%2)", d->mNameMap[id], id);
161  } else {
162  s = i18n("Unnamed - ID: %1", id);
163  }
164  } else {
165  // Should _never_ happen
166  s = i18np("%1 unregistered", "%1 unregistered", id);
167  }
168  return s;
169 }
170 
172 {
173  // Prevent direct emitting until all is loaded
174  lockDirectEmit();
175  uint count, i;
176  stream >> count;
177  qDebug() << ":" << count << "KGameProperty objects";
178  for (i = 0; i < count; ++i) {
179  processMessage(stream, id(), false);
180  }
181  qint16 cookie;
182  stream >> cookie;
183  if (cookie == KPLAYERHANDLER_LOAD_COOKIE) {
184  qDebug() << " KGamePropertyHandler loaded properly";
185  } else {
186  qCCritical(KDEGAMESPRIVATE_LOG) << "KGamePropertyHandler loading error. probably format error";
187  }
188  // Allow direct emitting (if no other lock still holds)
190  return true;
191 }
192 
194 {
195  qDebug() << ":" << d->mIdDict.count() << "KGameProperty objects";
196  stream << (uint)d->mIdDict.count();
197  QMultiHashIterator<int, KGamePropertyBase *> it(d->mIdDict);
198  while (it.hasNext()) {
199  it.next();
200  KGamePropertyBase *base = it.value();
201  if (base) {
202  KGameMessage::createPropertyHeader(stream, base->id());
203  base->save(stream);
204  }
205  }
206  stream << (qint16)KPLAYERHANDLER_LOAD_COOKIE;
207  return true;
208 }
209 
211 {
212  // qDebug() << ":" << d->mDefaultPolicy;
213  return d->mDefaultPolicy;
214 }
216 {
217  // qDebug() << ":" << p;
218  d->mDefaultPolicy = p;
219  d->mDefaultUserspace = userspace;
220  QMultiHashIterator<int, KGamePropertyBase *> it(d->mIdDict);
221  while (it.hasNext()) {
222  it.next();
223  if (!userspace || it.value()->id() >= KGamePropertyBase::IdUser) {
224  it.value()->setPolicy((KGamePropertyBase::PropertyPolicy)p);
225  }
226  }
227 }
228 
230 {
231  QMultiHashIterator<int, KGamePropertyBase *> it(d->mIdDict);
232  while (it.hasNext()) {
233  it.next();
234  it.value()->unlock();
235  }
236 }
237 
239 {
240  QMultiHashIterator<int, KGamePropertyBase *> it(d->mIdDict);
241  while (it.hasNext()) {
242  it.next();
243  it.value()->lock();
244  }
245 }
246 
248 {
249  return d->mUniqueId++;
250 }
251 
253 {
254  QMultiHashIterator<int, KGamePropertyBase *> it(d->mIdDict);
255  while (it.hasNext()) {
256  it.next();
257  if (it.value()->isDirty()) {
258  it.value()->sendProperty();
259  }
260  }
261 }
262 
263 /* Fire all property signal changed which are collected in
264  * the queque
265  */
267 {
268  d->mIndirectEmit++;
269 }
270 
272 {
273  // If the flag is <=0 we emit the queued signals
274  d->mIndirectEmit--;
275  if (d->mIndirectEmit <= 0) {
276  while (!d->mSignalQueue.isEmpty()) {
277  KGamePropertyBase *prop = d->mSignalQueue.dequeue();
278  // qDebug() << "emitting signal for" << prop->id();
280  }
281  }
282 }
283 
285 {
286  // If the indirect flag is set (load and network transmit)
287  // we cannot emit the signals directly as it can happened that
288  // a signal causes an access to a property which is e.g. not
289  // yet loaded or received
290 
291  if (d->mIndirectEmit > 0) {
292  // Queque the signal
293  d->mSignalQueue.enqueue(prop);
294  } else {
295  // directly emit
297  }
298 }
299 
301 {
302  bool sent = false;
303  Q_EMIT signalSendMessage(id(), s, &sent);
304  return sent;
305 }
306 
308 {
309  if (d->mIdDict.find(id) == d->mIdDict.end())
310  return nullptr;
311  return *(d->mIdDict.find(id));
312 }
313 
315 {
316  // Note: Hash iterator method 'toFront()' crashes when applied to first item.
317  // Therefore we get the keys as list first.
318  const QList<int> list = d->mIdDict.keys();
319  for (int key : list) {
320  KGamePropertyBase *p = d->mIdDict.value(key);
321  p->unregisterData();
322  if (d->mIdDict.find(p->id()) != d->mIdDict.end()) {
323  // shouldn't happen - but if mOwner in KGamePropertyBase is NULL
324  // this might be possible
325  removeProperty(p);
326  }
327  }
328 }
329 
331 {
332  return d->mIdDict;
333 }
334 
336 {
337  if (!prop) {
338  return i18n("NULL pointer");
339  }
340 
341  QString value;
342 
343  const type_info *t = prop->typeinfo();
344  if (*t == typeid(int)) {
345  value = QString::number(((KGamePropertyInt *)prop)->value());
346  } else if (*t == typeid(unsigned int)) {
347  value = QString::number(((KGamePropertyUInt *)prop)->value());
348  } else if (*t == typeid(long int)) {
349  value = QString::number(((KGameProperty<qint64> *)prop)->value());
350  } else if (*t == typeid(unsigned long int)) {
351  value = QString::number(((KGameProperty<quint64> *)prop)->value());
352  } else if (*t == typeid(QString)) {
353  value = ((KGamePropertyQString *)prop)->value();
354  } else if (*t == typeid(qint8)) {
355  value = ((KGamePropertyBool *)prop)->value() ? i18n("True") : i18n("False");
356  } else {
357  Q_EMIT signalRequestValue(prop, value);
358  }
359 
360  if (value.isNull()) {
361  value = i18n("Unknown");
362  }
363  return value;
364 }
365 
367 {
368  qDebug() << "-----------------------------------------------------------";
369  qDebug() << "KGamePropertyHandler:: Debug this=" << this;
370 
371  qDebug() << " Registered properties: (Policy,Lock,Emit,Optimized, Dirty)";
372  QMultiHashIterator<int, KGamePropertyBase *> it(d->mIdDict);
373  while (it.hasNext()) {
374  it.next();
375  KGamePropertyBase *p = it.value();
376  qDebug() << " " << p->id() << ": p=" << p->policy() << "l=" << p->isLocked() << "e=" << p->isEmittingSignal() << "o=" << p->isOptimized()
377  << "d=" << p->isDirty();
378  }
379  qDebug() << "-----------------------------------------------------------";
380 }
381 
382 #include "moc_kgamepropertyhandler.cpp"
void flush()
Sends all properties which are marked dirty over the network.
bool isNull() const const
bool processMessage(QDataStream &stream, int id, bool isSender)
Main message process function.
bool isDirty() const
static void createPropertyHeader(QDataStream &msg, int id)
Creates a property header given the property id.
QString number(int n, int base)
virtual bool load(QDataStream &stream)
Loads properties from the datastream.
Q_EMITQ_EMIT
void unlockProperties()
Calls KGamePropertyBase::setReadOnly(false) for all properties of this player.
bool isOptimized() const
See also setOptimize.
void unlockDirectEmit()
Removes the lock from the emitting of property signals.
void Debug()
Writes some debug output to the console.
KGamePropertyBase * find(int id)
void registerHandler(int id, const QObject *receiver, const char *send, const char *emit)
Register the handler with a parent.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void signalPropertyChanged(KGamePropertyBase *)
This is emitted by a property.
PropertyPolicy
The policy of the property.
static void extractPropertyHeader(QDataStream &msg, int &id)
Retrieves the property id from a property message header.
virtual bool save(QDataStream &stream)
Saves properties into the datastream.
void emitSignal(KGamePropertyBase *data)
called by a property to emit a signal This call is simply forwarded to the parent object
QString i18n(const char *text, const TYPE &arg...)
bool isLocked() const
A locked property can only be changed by the player who has set the lock.
bool removeProperty(KGamePropertyBase *data)
Removes a property from the handler.
void signalRequestValue(KGamePropertyBase *property, QString &value)
If you call propertyValue with a non-standard KGameProperty it is possible that the value cannot auto...
bool addProperty(KGamePropertyBase *data, const QString &name=QString())
Adds a KGameProperty property to the handler.
bool isEmpty() const const
A collection class for KGameProperty objects.
virtual void save(QDataStream &s)=0
Write the value into a stream.
Base class of KGameProperty.
Definition: kgameproperty.h:36
int uniquePropertyId()
returns a unique property ID starting called usually with a base of KGamePropertyBase::IdAutomatic.
virtual const type_info * typeinfo()
KGamePropertyHandler(QObject *parent=nullptr)
Construct an unregistered KGamePropertyHandler.
void setPolicy(KGamePropertyBase::PropertyPolicy p, bool userspace=true)
Set the policy for all kgame variables which are currently registered in the KGame property handler.
QString propertyValue(KGamePropertyBase *property)
In several situations you just want to have a QString of a KGameProperty object.
void lockProperties()
Calls KGamePropertyBase::setReadOnly(true) for all properties of this handler.
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString propertyName(int id) const
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.
virtual void command(QDataStream &stream, int msgid, bool isSender=false)
send a command to advanced properties like arrays
KGamePropertyBase::PropertyPolicy policy()
Returns the default policy for this property handler.
static void extractPropertyCommand(QDataStream &msg, int &pid, int &cmd)
Retrieves the property id from a property message header.
PropertyPolicy policy() const
virtual void load(QDataStream &s)=0
This will read the value of this property from the stream.
QMultiHash< int, KGamePropertyBase * > & dict() const
Reference to the internal dictionary.
void setId(int id)
Use id as new ID for this KGamePropertyHandler.
void lockDirectEmit()
Called by the KGame or KPlayer object or the handler itself to delay emitting of signals.
bool isEmittingSignal() const
See also setEmittingSignal.
void clear()
Clear the KGamePropertyHandler.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Nov 28 2023 03:50:18 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.