File indexing completed on 2024-06-16 03:57:56

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