File indexing completed on 2024-09-22 03:48:33
0001 /* 0002 This file is part of the KDE games library 0003 SPDX-FileCopyrightText: 2001 Andreas Beckermann <b_mann@gmx.de> 0004 SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only 0007 */ 0008 0009 #ifndef __KGAMEPROPERTYHANDLER_H_ 0010 #define __KGAMEPROPERTYHANDLER_H_ 0011 0012 // own 0013 #include "kdegamesprivate_export.h" 0014 #include "kgameproperty.h" 0015 // Qt 0016 #include <QMultiHash> 0017 #include <QObject> 0018 // Std 0019 #include <memory> 0020 0021 class QDataStream; 0022 class KGame; 0023 // class KGamePropertyBase; 0024 0025 class KGamePropertyHandlerPrivate; // wow - what a name ;-) 0026 0027 /** 0028 * \class KGamePropertyHandler kgamepropertyhandler.h <KGame/KGamePropertyHandler> 0029 * 0030 * @short A collection class for KGameProperty objects 0031 * 0032 * The KGamePropertyHandler class is some kind of a collection class for 0033 * KGameProperty. You usually don't have to create one yourself, as both 0034 * KPlayer and KGame provide a handler. In most cases you do not even have 0035 * to care about the KGamePropertHandler. KGame and KPlayer implement 0036 * all features of KGamePropertyHandler so you will rather use it there. 0037 * 0038 * You have to use the KGamePropertyHandler as parent for all KGameProperty 0039 * objects but you can also use KPlayer or KGame as parent - then 0040 * KPlayer::dataHandler or KGame::dataHandler will be used. 0041 * 0042 * Every KGamePropertyHandler must have - just like every KGameProperty - 0043 * a unique ID. This ID is provided either in the constructor or in 0044 * registerHandler. The ID is used to assign an incoming message (e.g. a changed 0045 * property) to the correct handler. Inside the handler the property ID is used 0046 * to change the correct property. 0047 * 0048 * The constructor or registerHandler takes 3 additional arguments: a 0049 * receiver and two slots. The first slot is connected to 0050 * signalSendMessage, the second to signalPropertyChanged. You must provide 0051 * these in order to use the KGamePropertyHandler. 0052 * 0053 * The most important function of KGamePropertyHandler is processMessage 0054 * which assigns an incoming value to the correct property. 0055 * 0056 * A KGamePropertyHandler is also used - indirectly using emitSignal - to 0057 * emit a signal when the value of a property changes. This is done this way 0058 * because a KGameProperty does not inherit QObject because of memory 0059 * advantages. Many games can have dozens or even hundreds of KGameProperty 0060 * objects so every additional variable in KGameProperty would be 0061 * multiplied. 0062 */ 0063 class KDEGAMESPRIVATE_EXPORT KGamePropertyHandler : public QObject 0064 { 0065 Q_OBJECT 0066 0067 public: 0068 /** 0069 * Construct an unregistered KGamePropertyHandler 0070 * 0071 * You have to call registerHandler before you can use this 0072 * handler! 0073 */ 0074 explicit KGamePropertyHandler(QObject *parent = nullptr); 0075 0076 /** 0077 * Construct a registered handler. 0078 * 0079 * @see registerHandler 0080 */ 0081 KGamePropertyHandler(int id, const QObject *receiver, const char *sendf, const char *emitf, QObject *parent = nullptr); 0082 ~KGamePropertyHandler() override; 0083 0084 /** 0085 * Register the handler with a parent. This is to use 0086 * if the constructor without arguments has been chosen. 0087 * Otherwise you need not call this. 0088 * 0089 * @param id The id of the message to listen for 0090 * @param receiver The object that will receive the signals of 0091 * KGamePropertyHandler 0092 * @param send A slot that is being connected to signalSendMessage 0093 * @param emit A slot that is being connected to signalPropertyChanged 0094 */ 0095 void registerHandler(int id, const QObject *receiver, const char *send, const char *emit); 0096 0097 /** 0098 * Main message process function. This has to be called by 0099 * the parent's message event handler. If the id of the message 0100 * agrees with the id of the handler, the message is extracted 0101 * and processed. Otherwise false is returned. 0102 * Example: 0103 * \code 0104 * if (mProperties.processMessage(stream,msgid,sender==gameId())) return ; 0105 * \endcode 0106 * 0107 * @param stream The data stream containing the message 0108 * @param id the message id of the message 0109 * @param isSender Whether the receiver is also the sender 0110 * @return true on message processed otherwise false 0111 */ 0112 bool processMessage(QDataStream &stream, int id, bool isSender); 0113 0114 /** 0115 * @return the id of the handler 0116 */ 0117 int id() const; 0118 0119 /** 0120 * Adds a KGameProperty property to the handler 0121 * @param data the property 0122 * @param name A description of the property, which will be returned by 0123 * propertyName. This is used for debugging 0124 * @return true on success 0125 */ 0126 bool addProperty(KGamePropertyBase *data, const QString &name = QString()); 0127 0128 /** 0129 * Removes a property from the handler 0130 * @param data the property 0131 * @return true on success 0132 */ 0133 bool removeProperty(KGamePropertyBase *data); 0134 0135 /** 0136 * returns a unique property ID starting called usually with a base of 0137 * KGamePropertyBase::IdAutomatic. This is used internally by 0138 * the property base to assign automatic id's. Not much need to 0139 * call this yourself. 0140 */ 0141 int uniquePropertyId(); 0142 0143 /** 0144 * Loads properties from the datastream 0145 * 0146 * @param stream the datastream to load from 0147 * @return true on success otherwise false 0148 */ 0149 virtual bool load(QDataStream &stream); 0150 0151 /** 0152 * Saves properties into the datastream 0153 * 0154 * @param stream the datastream to save to 0155 * @return true on success otherwise false 0156 */ 0157 virtual bool save(QDataStream &stream); 0158 0159 /** 0160 * called by a property to send itself into the 0161 * datastream. This call is simply forwarded to 0162 * the parent object 0163 */ 0164 bool sendProperty(QDataStream &s); 0165 0166 void sendLocked(bool l); 0167 0168 /** 0169 * called by a property to emit a signal 0170 * This call is simply forwarded to 0171 * the parent object 0172 */ 0173 void emitSignal(KGamePropertyBase *data); 0174 0175 /** 0176 * @param id The ID of the property 0177 * @return A name of the property which can be used for debugging. Don't 0178 * depend on this function! It it possible not to provide a name or to 0179 * provide the same name for multiple properties! 0180 */ 0181 QString propertyName(int id) const; 0182 0183 /** 0184 * @param id The ID of the property. See KGamePropertyBase::id 0185 * @return The KGameProperty this ID is assigned to 0186 */ 0187 KGamePropertyBase *find(int id); 0188 0189 /** 0190 * Clear the KGamePropertyHandler. Note that the properties are 0191 * <em>not</em> deleted so if you created your KGameProperty 0192 * objects dynamically like 0193 * \code 0194 * KGamePropertyInt* myProperty = new KGamePropertyInt(id, dataHandler()); 0195 * \endcode 0196 * you also have to delete it: 0197 * \code 0198 * dataHandler()->clear(); 0199 * delete myProperty; 0200 * \endcode 0201 */ 0202 void clear(); 0203 0204 /** 0205 * Use id as new ID for this KGamePropertyHandler. This is used 0206 * internally only. 0207 */ 0208 void setId(int id); // AB: TODO: make this protected in KGamePropertyHandler!! 0209 0210 /** 0211 * Calls KGamePropertyBase::setReadOnly(false) for all properties of this 0212 * player. See also lockProperties 0213 */ 0214 void unlockProperties(); 0215 0216 /** 0217 * Set the policy for all kgame variables which are currently registered in 0218 * the KGame property handler. See KGamePropertyBase::setPolicy 0219 * 0220 * @param p is the new policy for all properties of this handler 0221 * @param userspace if userspace is true (default) only user properties are changed. 0222 * Otherwise the system properties are also changed. 0223 */ 0224 void setPolicy(KGamePropertyBase::PropertyPolicy p, bool userspace = true); 0225 0226 /** 0227 * Called by the KGame or KPlayer object or the handler itself to delay 0228 * emitting of signals. Locking keeps a counter and unlock is only achieved 0229 * when every lock is canceled by an unlock. 0230 * While this is set signals are queued and only emitted after this 0231 * is reset. Its deeper meaning is to prevent inconsistencies in a game 0232 * load or network transfer where a emit could access a property not 0233 * yet loaded or transmitted. Calling this by yourself you better know 0234 * what your are doing. 0235 */ 0236 void lockDirectEmit(); 0237 0238 /** 0239 * Removes the lock from the emitting of property signals. Corresponds to 0240 * the lockIndirectEmits 0241 */ 0242 void unlockDirectEmit(); 0243 0244 /** 0245 * Returns the default policy for this property handler. All properties 0246 * registered newly, will have this property. 0247 */ 0248 KGamePropertyBase::PropertyPolicy policy(); 0249 0250 /** 0251 * Calls KGamePropertyBase::setReadOnly(true) for all properties of this 0252 * handler 0253 * 0254 * Use with care! This will even lock the core properties, like name, 0255 * group and myTurn!! 0256 * 0257 * @see unlockProperties 0258 */ 0259 void lockProperties(); 0260 0261 /** 0262 * Sends all properties which are marked dirty over the network. This will 0263 * make a forced synchronization of the properties and mark them all not dirty. 0264 */ 0265 void flush(); 0266 0267 /** 0268 * Reference to the internal dictionary 0269 */ 0270 QMultiHash<int, KGamePropertyBase *> &dict() const; 0271 0272 /** 0273 * In several situations you just want to have a QString of a 0274 * KGameProperty object. This 0275 * function will provide you with such a QString for all the types 0276 * used inside of all KGame classes. If you have a non-standard 0277 * property (probably a self defined class or something like this) you 0278 * also need to connect to signalRequestValue to make this function 0279 * useful. 0280 * @param property Return the value of this KGameProperty 0281 * @return The value of a KGameProperty 0282 */ 0283 QString propertyValue(KGamePropertyBase *property); 0284 0285 /** 0286 * Writes some debug output to the console. 0287 */ 0288 void Debug(); 0289 0290 Q_SIGNALS: 0291 /** 0292 * This is emitted by a property. KGamePropertyBase::emitSignal 0293 * calls emitSignal which emits this signal. 0294 * 0295 * This signal is emitted whenever the property is changed. Note that 0296 * you can switch off this behaviour using 0297 * KGamePropertyBase::setEmittingSignal in favor of performance. Note 0298 * that you won't experience any performance loss using signals unless 0299 * you use dozens or hundreds of properties which change very often. 0300 */ 0301 void signalPropertyChanged(KGamePropertyBase *); 0302 0303 /** 0304 * This signal is emitted when a property needs to be sent. Only the 0305 * parent has to react to this. 0306 * @param msgid The id of the handler 0307 * @param sent set this to true if the property was sent successfully - 0308 * otherwise don't touch 0309 */ 0310 void signalSendMessage(int msgid, QDataStream &, bool *sent); // AB shall we change bool* into bool& again? 0311 0312 /** 0313 * If you call propertyValue with a non-standard KGameProperty 0314 * it is possible that the value cannot automatically be converted into a 0315 * QString. Then this signal is emitted and asks you to provide the 0316 * correct value. You probably want to use something like this to achieve 0317 * this: 0318 * \code 0319 * #include <typeinfo> 0320 * void slotRequestValue(KGamePropertyBase* p, QString& value) 0321 * { 0322 * if (*(p->typeinfo()) == typeid(MyType) { 0323 * value = QString(((KGameProperty<MyType>*)p)->value()); 0324 * } 0325 * } 0326 * \endcode 0327 * 0328 * @param property The KGamePropertyBase the value is requested for 0329 * @param value The value of this property. You have to set this. 0330 */ 0331 void signalRequestValue(KGamePropertyBase *property, QString &value); 0332 0333 private: 0334 friend class KGamePropertyHandlerPrivate; 0335 std::unique_ptr<KGamePropertyHandlerPrivate> const d; 0336 0337 Q_DISABLE_COPY(KGamePropertyHandler) 0338 }; 0339 0340 #endif