File indexing completed on 2024-05-12 04:06:05

0001 /*
0002     This file is part of the KDE games library
0003     SPDX-FileCopyrightText: 2001 Andreas Beckermann <b_mann@gmx.de>
0004     SPDX-FileCopyrightText: 2003 Nicolas Hadacek <hadacek@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #ifndef KGAMEHIGHSCORE_H
0010 #define KGAMEHIGHSCORE_H
0011 
0012 // own
0013 #include <kdegames_export.h>
0014 // Qt
0015 #include <QObject>
0016 // Std
0017 #include <memory>
0018 
0019 class KConfig;
0020 
0021 /**
0022  * \class KGameHighscore kgamehighscore.h <KGameHighscore>
0023  *
0024  * @short Class for managing highscore tables
0025  *
0026  * This is the KDE class for saving and reading highscore tables. It offers the
0027  * possibility for system-wide highscore tables (cmake with e.g.
0028  * -DHIGHSCORE_DIRECTORY=/var/games) and a theoretically unlimited number of
0029  * entries.
0030  *
0031  * You can specify different "keys" for an entry - just like the KConfig
0032  * keys. But it will be prefixed with the number of the entry. For example you
0033  * will probably use something like this to save the name of the player on the
0034  * top of the list (ie the winner):
0035  * \code
0036  * highscore->writeEntry(1, "name", myPlayer->name());
0037  * \endcode
0038  * Note that it does not really matter if you use "0" or "1" as the first entry
0039  * of the list as long as your program always uses the same for the first
0040  * entry. I recommend to use "1", as several convenience methods use this.
0041  *
0042  * You can also specify different groups using setHighscoreGroup. Just
0043  * like the keys mentioned above the groups behave like groups in KConfig
0044  * but are prefixed with "KHighscore_". The default group is just "KHighscore".
0045  * You might use this e.g. to create different highscore tables like
0046  * \code
0047  * table->setHighscoreGroup("Easy");
0048  * // write the highscores for level "easy" to the table
0049  * writeEasyHighscores(table);
0050  *
0051  * table->setHighscore("Player_1");
0052  * // write player specific highscores to the table
0053  * writePlayerHighscores(table);
0054  * \endcode
0055  * As you can see above you can also use this to write the highscores of a
0056  * single player, so the "best times" of a player. To write highscores for a
0057  * specific player in a specific level you will have to use a more complex way:
0058  * \code
0059  * QString group = QStringLiteral("%1_%2").arg(player).arg(level);
0060  * table->setGroup(group);
0061  * writeHighscore(table, player, level);
0062  * \endcode
0063  *
0064  * Also note that you MUST NOT mark the key or the group for translation! I.e.
0065  * don't use i18n() for the keys or groups! Here is the code to read the above
0066  * written entry:
0067  * \code
0068  * QString firstName = highscore->readEntry(0, "name");
0069  * \endcode
0070  * Easy, what?
0071  * @author Andreas Beckermann <b_mann@gmx.de>
0072  */
0073 class KDEGAMES_EXPORT KGameHighscore : public QObject
0074 {
0075     Q_OBJECT
0076 
0077 public:
0078     /**
0079      * Constructor.
0080      *
0081      * @param forceLocal if true, the local highscore file is used even
0082      * when the configuration has been set to use a system-wide file. This
0083      * is convenient for converting highscores from legacy applications.
0084      * @param parent parent widget for this widget
0085      */
0086     explicit KGameHighscore(bool forceLocal = true, QObject *parent = nullptr);
0087 
0088     /**
0089      * Read the current state of the highscore file. Remember that when
0090      * it's not locked for writing, this file can change at any time.
0091      * (This method is only useful for a system-wide highscore file).
0092      */
0093     void readCurrentConfig();
0094 
0095     /**
0096      * This method open the system-wide highscore file using the effective
0097      * group id of the game executable (which should be "games"). The
0098      * effective group id is completely dropped afterwards.
0099      *
0100      * Note: this method should be called in main() before creating a
0101      * KApplication and doing anything else (KApplication checks that the
0102      * program is not suid/sgid and will exit the program for security
0103      * reason if it is the case).
0104      */
0105     static void init(const char *appname);
0106 
0107     /**
0108      * Lock the system-wide highscore file for writing (does nothing and
0109      * return true if the local file is used).
0110      * You should perform writing without GUI interaction to avoid
0111      * blocking and don't forget to unlock the file as soon as possible
0112      * with writeAndUnlock().
0113      *
0114      * If the config file cannot be locked,
0115      * the method waits for 1 second and, if it failed again, displays
0116      * a message box asking for retry or cancel.
0117      * @param widget used as the parent of the message box.
0118      *
0119      * @return false on error or if the config file is locked by another
0120      * process. In such case, the config stays read-only.
0121      */
0122     bool lockForWriting(QWidget *widget = nullptr);
0123 
0124     /**
0125      * Effectively write and unlock the system-wide highscore file
0126      * (@see lockForWriting).
0127      * If using a local highscore file, it will sync the config.
0128      */
0129     void writeAndUnlock();
0130 
0131     /**
0132      * @return true if the highscore file is locked or if a local
0133      * file is used.
0134      */
0135     bool isLocked() const;
0136 
0137     /**
0138      * Destructor.
0139      * If necessary, write and unlock the highscore file.
0140      */
0141     ~KGameHighscore() override;
0142 
0143     /**
0144      * @param entry The number of the entry / the placing of the player
0145      * @param key A key for this entry. E.g. "name" for the name of the
0146      * player. Nearly the same as the usual keys in KConfig - but they
0147      * are prefixed with the entry number
0148      * @param value The value of this entry
0149      */
0150     void writeEntry(int entry, const QString &key, const QString &value);
0151 
0152     /**
0153      * This is an overloaded member function, provided for convenience.
0154      * It differs from the above function only in what argument(s) it accepts.
0155      */
0156     void writeEntry(int entry, const QString &key, int value);
0157 
0158     /**
0159      * This is an overloaded member function, provided for convenience.
0160      * It differs from the above function only in what argument(s) it accepts.
0161      * See KConfigBase documentation for allowed QVariant::Type.
0162      */
0163     void writeEntry(int entry, const QString &key, const QVariant &value);
0164 
0165     /**
0166      * Reads an entry from the highscore table.
0167      * @param entry The number of the entry / the placing to be read
0168      * @param key The key of the entry. E.g. "name" for the name of the
0169      * player. Nearly the same as the usual keys in KConfig - but they
0170      * are prefixed with the entry number
0171      * @param pDefault This will be used as default value if the key+pair
0172      * entry can't be found.
0173      * @return The value of this entry+key pair or pDefault if the entry+key
0174      * pair doesn't exist
0175      */
0176     QString readEntry(int entry, const QString &key, const QString &pDefault = QString()) const;
0177 
0178     /**
0179      * Read a numeric value.
0180      * @param entry The number of the entry / the placing to be read
0181      * @param key The key of the entry. E.g. "name" for the name of the
0182      * player. Nearly the same as the usual keys in KConfig - but they
0183      * are prefixed with the entry number
0184      * @param pDefault This will be used as default value if the key+pair
0185      * entry can't be found.
0186      * @return The value of this entry+key pair or pDefault if the entry+key
0187      * pair doesn't exist
0188      */
0189     int readNumEntry(int entry, const QString &key, int pDefault = -1) const;
0190 
0191     /**
0192      * Read a QVariant entry.
0193      * See KConfigBase documentation for allowed QVariant::Type.
0194      *
0195      * @return the value of this entry+key pair or pDefault if the entry+key
0196      * pair doesn't exist or
0197      */
0198     QVariant readPropertyEntry(int entry, const QString &key, const QVariant &pDefault) const;
0199 
0200     /**
0201      * @return True if the highscore table contains the entry/key pair,
0202      * otherwise false
0203      */
0204     bool hasEntry(int entry, const QString &key) const;
0205 
0206     /**
0207      * Reads a list of entries from the highscore table starting at 1 until
0208      * lastEntry. If an entry between those numbers doesn't exist the
0209      * function aborts reading even if after the missing entry is an
0210      * existing one. The first entry of the list is the first placing, the
0211      * last on is the last placing.
0212      * @return A list of the entries of this key. You could also call
0213      * readEntry(i, key) where i is from 1 to 20. Note that this function
0214      * depends on "1" as the first entry!
0215      * @param key The key of the entry. E.g. "name" for the name of the
0216      * player. Nearly the same as the usual keys in KConfig - but they
0217      * are prefixed with the entry number
0218      * @param lastEntry the last entry which will be includes into the list.
0219      * 1 will include a list with maximal 1 entry - 20 a list with maximal
0220      * 20 entries. If lastEntry is <= 0 then rading is only stopped when
0221      * when an entry does not exist.
0222      */
0223     QStringList readList(const QString &key, int lastEntry = 20) const;
0224 
0225     /**
0226      * Writes a list of entries to the highscore table.
0227      *
0228      * The first entry is prefixed with "1". Using this method is a short
0229      * way of calling writeEntry(i, key, list[i]) from i = 1 to
0230      * list.count()
0231      * @param key A key for the entry. E.g. "name" for the name of the
0232      * player. Nearly the same as the usual keys in KConfig - but they
0233      * are prefixed with the entry number
0234      * @param list The list of values
0235      */
0236     void writeList(const QString &key, const QStringList &list);
0237 
0238     /**
0239      * You can use this function to indicate whether KGameHighscore created a
0240      * highscore table before and - if not - read your old (non-KGameHighscore)
0241      * table instead.
0242      * This way you can safely read an old table and save it using
0243      * KGameHighscore without losing any data
0244      * @return Whether a highscore table exists.
0245      */
0246     bool hasTable() const;
0247 
0248     /**
0249      * Set the new highscore group. The group is being prefixed with
0250      * "KHighscore_" in the table.
0251      * @param groupname The new groupname. E.g. use "easy" for the easy
0252      * level of your game. If you use QString() (the default) the
0253      * default group is used.
0254      */
0255     void setHighscoreGroup(const QString &groupname = QString());
0256 
0257     /**
0258      * Returns a list of group names without the KHighscore_ prexix.
0259      * E.g, "KHighscore", "KHighscore_Easy", "KHighscore_Medium"
0260      * will return "", "Easy", "Medium"
0261      *
0262      * @return A list of highscore groups.
0263      */
0264     QStringList groupList() const;
0265 
0266     /**
0267      * @return The currently used group. This doesn't contain the prefix
0268      * ("KHighscore_") but the same as setHighscoreGroup uses. The
0269      * default is QString()
0270      */
0271     QString highscoreGroup() const;
0272 
0273 protected:
0274     /**
0275      * @return A groupname to be used in KConfig. Used internally to
0276      * prefix the value from highscoreGroup() with "KHighscore_"
0277      */
0278     QString group() const;
0279 
0280     /**
0281      * @return A pointer to the KConfig object to be used. This is
0282      * either KGlobal::config() (default) or a KSimpleConfig object for
0283      * a system-wide highscore file.
0284      */
0285     KConfig *config() const;
0286 
0287     void init(bool forceLocal);
0288 
0289 private:
0290     std::unique_ptr<class KGameHighscorePrivate> const d_ptr;
0291     Q_DECLARE_PRIVATE(KGameHighscore)
0292 };
0293 
0294 #endif