summaryrefslogtreecommitdiffstats
path: root/libkdegames/highscore/khighscore.h
blob: b1e3d25f621501eb8bf4ee44cff42fba49855c1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
    This file is part of the KDE games library
    Copyright (C) 2001 Andreas Beckermann ([email protected])
    Copyright (C) 2003 Nicolas Hadacek <[email protected]>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/
/*
    $Id$
*/
#ifndef __KHIGHSCORE_H__
#define __KHIGHSCORE_H__

#include <qstring.h>
#include <qobject.h>
#include <kdemacros.h>
class KConfig;
class KFileLock;
class KRawConfig;
class KHighscorePrivate;

/**
 * @short Class for managing highscore tables
 *
 * This is the KDE class for saving and reading highscore tables. It offers the
 * possibility for system-wide highscore tables (configure with e.g.
 * --enable-highscore-dir=/var/games) and a theoretically unlimited number of
 * entries.
 *
 * You can specify different "keys" for an entry - just like the KConfig
 * keys. But it will be prefixed with the number of the entry. For example you
 * will probably use something like this to save the name of the player on the
 * top of the list (ie the winner):
 * \code
 * highscore->writeEntry(1, "name", myPlayer->name());
 * \endcode
 * Note that it doesn't really matter if you use "0" or "1" as the first entry
 * of the list as long as your program always uses the same for the first
 * entry. I recommend to use "1", as several convenience methods use this.
 *
 * You can also specify different groups using setHighscoreGroup. Just
 * like the keys mentioned above the groups behave like groups in KConfig
 * but are prefixed with "KHighscore_". The default group is just "KHighscore".
 * You might use this e.g. to create different highscore tables like
 * \code
 * table->setHighscoreGroup("Easy");
 * // write the highscores for level "easy" to the table
 * writeEasyHighscores(table);
 *
 * table->setHighscore("Player_1");
 * // write player specific highscores to the table
 * writePlayerHighscores(table);
 * \endcode
 * As you can see above you can also use this to write the highscores of a
 * single player, so the "best times" of a player. To write highscores for a
 * specific player in a specific level you will have to use a more complex way:
 * \code
 * QString group = QString("%1_%2").arg(player).arg(level);
 * table->setGroup(group);
 * writeHighscore(table, player, level);
 * \endcode
 *
 * Also note that you MUST NOT mark the key or the group for translation! I.e.
 * don't use i18n() for the keys or groups! Here is the code to read the above
 * written entry:
 * \code
 * QString firstName = highscore->readEntry(0, "name");
 * \endcode
 * Easy, what?
 * @author Andreas Beckermann <[email protected]>
 **/
class KDE_EXPORT KHighscore : public QObject
{
	Q_OBJECT
public:
        /** @obsolete
         * Constructor. The highscore file is forced to be local to support
         * games using the old behaviour.
         */
	KHighscore(QObject* parent = 0);

        /**
         * Constructor.
         *
         * @param forceLocal if true, the local highscore file is used even
         * when the configuration has been set to use a system-wide file. This
         * is convenient for converting highscores from legacy applications.
	 * @param parent parent widget for this widget
	 * @since 3.2
         */
        KHighscore(bool forceLocal, QObject *parent);

        /**
         * Read the current state of the highscore file. Remember that when
         * it's not locked for writing, this file can change at any time.
         * (This method is only useful for a system-wide highscore file).
	 * @since 3.2
         */
        void readCurrentConfig();

        /** @since 3.2
         * This method open the system-wide highscore file using the effective
         * group id of the game executable (which should be "games"). The
         * effective group id is completely dropped afterwards.
         *
         * Note: this method should be called in main() before creating a
         * KApplication and doing anything else (KApplication checks that the
         * program is not suid/sgid and will exit the program for security
         * reason if it is the case).
         */
        static void init(const char *appname);

        /** @since 3.2
         * Lock the system-wide highscore file for writing (does nothing and
         * return true if the local file is used).
         * You should perform writing without GUI interaction to avoid
         * blocking and don't forget to unlock the file as soon as possible
         * with writeAndUnlock().
         *
         * If the config file cannot be locked,
         * the method waits for 1 second and, if it failed again, displays
         * a message box asking for retry or cancel.
         * @param widget used as the parent of the message box.
         *
         * @return false on error or if the config file is locked by another
         * process. In such case, the config stays read-only.
         */
        bool lockForWriting(QWidget *widget = 0);

        /**
         * Effectively write and unlock the system-wide highscore file
         * (@see lockForWriting).
         * If using a local highscore file, it will sync the config.
	 * @since 3.2
         */
        void writeAndUnlock();

        /**
         * @return true if the highscore file is locked or if a local
         * file is used.
	 *  @since 3.2
         */
        bool isLocked() const;

        /**
         * Destructor.
         * If necessary, write and unlock the highscore file.
         */
	~KHighscore();

	/**
	 * @param entry The number of the entry / the placing of the player
	 * @param key A key for this entry. E.g. "name" for the name of the
	 * player. Nearly the same as the usual keys in KConfig - but they
	 * are prefixed with the entry number
	 * @param value The value of this entry
	 **/
	void writeEntry(int entry, const QString& key, const QString& value);

	/**
	 * This is an overloaded member function, provided for convenience.
	 * It differs from the above function only in what argument(s) it accepts.
	 **/
	void writeEntry(int entry, const QString& key, int value);

	/**
	 * This is an overloaded member function, provided for convenience.
	 * It differs from the above function only in what argument(s) it accepts.
	 * See KConfigBase documentation for allowed QVariant::Type.
	 **/
	void writeEntry(int entry, const QString& key, const QVariant &value);

	/**
	 * Reads an entry from the highscore table.
	 * @param entry The number of the entry / the placing to be read
	 * @param key The key of the entry. E.g. "name" for the name of the
	 * player. Nearly the same as the usual keys in KConfig - but they
	 * are prefixed with the entry number
	 * @param pDefault This will be used as default value if the key+pair
	 * entry can't be found.
	 * @return The value of this entry+key pair or pDefault if the entry+key
	 * pair doesn't exist
	 **/
	QString readEntry(int entry, const QString& key, const QString& pDefault = QString::null) const;

	/**
	 * Read a numeric value.
	 * @param entry The number of the entry / the placing to be read
	 * @param key The key of the entry. E.g. "name" for the name of the
	 * player. Nearly the same as the usual keys in KConfig - but they
	 * are prefixed with the entry number
	 * @param pDefault This will be used as default value if the key+pair
	 * entry can't be found.
	 * @return The value of this entry+key pair or pDefault if the entry+key
	 * pair doesn't exist
	 **/
	int readNumEntry(int entry, const QString& key, int pDefault = -1) const;

    /**
     * Read a QVariant entry.
     * See KConfigBase documentation for allowed QVariant::Type.
     *
     * @return the value of this entry+key pair or pDefault if the entry+key
     * pair doesn't exist or
     */
    QVariant readPropertyEntry(int entry, const QString &key, const QVariant &pDefault) const;

	/**
	 * @return True if the highscore table conatins the entry/key pair,
	 * otherwise false
	 **/
	bool hasEntry(int entry, const QString& key) const;

	/**
	 * Reads a list of entries from the highscore table starting at 1 until
	 * lastEntry. If an entry between those numbers doesn't exist the
	 * function aborts reading even if after the missing entry is an
	 * existing one. The first entry of the list is the first placing, the
	 * last on is the last placing.
	 * @return A list of the entries of this key. You could also call
	 * readEntry(i, key) where i is from 1 to 20. Note that this function
	 * depends on "1" as the first entry!
	 * @param key The key of the entry. E.g. "name" for the name of the
	 * player. Nearly the same as the usual keys in KConfig - but they
	 * are prefixed with the entry number
	 * @param lastEntry the last entry which will be includes into the list.
	 * 1 will include a list with maximal 1 entry - 20 a list with maximal
	 * 20 entries. If lastEntry is <= 0 then rading is only stopped when when an
	 * entry does not exist.
	 **/
	QStringList readList(const QString& key, int lastEntry = 20) const;

	/**
	 * Writes a list of entries to the highscore table.
	 *
	 * The first entry is prefixed with "1". Using this method is a short
	 * way of calling writeEntry(i, key, list[i]) from i = 1 to
	 * list.count()
	 * @param key A key for the entry. E.g. "name" for the name of the
	 * player. Nearly the same as the usual keys in KConfig - but they
	 * are prefixed with the entry number
	 * @param list The list of values
	 **/
	void writeList(const QString& key, const QStringList& list);

	/**
	 * @return Whether a highscore table exists. You can use this
	 * function to indicate whether KHighscore created a highscore table
	 * before and - if not - read your old (non-KHighscore) table instead.
	 * This way you can safely read an old table and save it using
	 * KHighscore without losing any data
	 **/
	bool hasTable() const;

        /** @obsolete
         * This does the same as writeAndUnlock().
         */
	void sync();

	/**
	 * Set the new highscore group. The group is being prefixed with
	 * "KHighscore_" in the table.
	 * @param groupname The new groupname. E.g. use "easy" for the easy
	 * level of your game. If you use QString::null (the default) the
	 * default group is used.
	 **/
	void setHighscoreGroup(const QString& groupname = QString::null);

	/**
	 * @return The currently used group. This doesn't contain the prefix
	 * ("KHighscore_") but the same as setHighscoreGroup uses. The
         * default is QString::null
	 **/
	const QString& highscoreGroup() const;

protected:
	/**
	 * @return A groupname to be used in KConfig. Used internally to
	 * prefix the value from highscoreGroup() with "KHighscore_"
	 **/
	QString group() const;

	/**
	 * @return A pointer to the KConfig object to be used. This is
	 * either kapp->config() (default) or a KSimpleConfig object for
         * a system-wide highscore file.
	 **/
	KConfig* config() const;

        void init(bool forceLocal);

private:
	KHighscorePrivate* d;

        static KFileLock *_lock; // lock on system-wide highscore file
        static KRawConfig *_config; // config for system-wide highscore file
};

#endif