KDEGames

kgamehighscore.cpp
1/*
2 This file is part of the KDE games library
3 SPDX-FileCopyrightText: 2001 Andreas Beckermann <b_mann@gmx.de>
4 SPDX-FileCopyrightText: 2003 Nicolas Hadacek <hadacek@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#include "kgamehighscore.h"
10
11// own
12#include <config-highscore.h>
13#include <kdegames_highscore_logging.h>
14// KF
15#include <KConfig>
16#include <KConfigGroup>
17#include <KLocalizedString>
18#include <KMessageBox>
19#include <KSharedConfig>
20#include <KStandardGuiItem>
21// Qt
22#include <QFile>
23#include <QLockFile>
24
25#ifndef WIN32
26#include <unistd.h> // sleep
27#else
28#include <qt_windows.h>
29#endif
30
31#define GROUP "KHighscore"
32
33class KGameHighscorePrivate
34{
35public:
36 KGameHighscorePrivate() = default;
37
38public:
39 QString group;
40 bool global;
41};
42
43class KGameHighscoreLockedConfig
44{
45public:
46 ~KGameHighscoreLockedConfig();
47 QLockFile *lock;
48 KConfig *config;
49};
50
51KGameHighscoreLockedConfig::~KGameHighscoreLockedConfig()
52{
53 delete lock;
54 delete config;
55}
56
57Q_GLOBAL_STATIC(KGameHighscoreLockedConfig, lockedConfig)
58
59KGameHighscore::KGameHighscore(bool forceLocal, QObject *parent)
60 : QObject(parent)
61 , d_ptr(new KGameHighscorePrivate)
62{
63 init(forceLocal);
64}
65
66void KGameHighscore::init(bool forceLocal)
67{
69
70#ifdef HIGHSCORE_DIRECTORY
71 d->global = !forceLocal;
72 if (d->global && lockedConfig->lock == 0) // If we're doing global highscores but not KFileLock has been set up yet
73 {
74 qCWarning(KDEGAMES_HIGHSCORE_LOG) << "KGameHighscore::init should be called before!!";
75 abort();
76 }
77#else
78 d->global = false;
79 Q_UNUSED(forceLocal);
80#endif
82}
83
85{
86 Q_D(const KGameHighscore);
87
88 return (d->global ? lockedConfig->lock->isLocked() : true);
89}
90
92{
94
95 if (d->global)
96 lockedConfig->config->reparseConfiguration();
97}
98
99void KGameHighscore::init(const char *appname)
100{
101#ifdef HIGHSCORE_DIRECTORY
102 const QString filename = QString::fromLocal8Bit("%1/%2.scores").arg(HIGHSCORE_DIRECTORY).arg(appname);
103
104 // int fd = fopen(filename.toLocal8Bit(), O_RDWR);
105 /*QFile file(filename);
106 if ( !file.open(QIODevice::ReadWrite) )
107 {
108 qCWarning(KDEGAMES_HIGHSCORE_LOG) << "cannot open global highscore file \""
109 << filename << "\"";
110 abort();
111 }*/
112
113 /*if (!(QFile::permissions(filename) & QFile::WriteOwner))
114 {
115 qCWarning(KDEGAMES_HIGHSCORE_LOG) << "cannot write to global highscore file \""
116 << filename << "\"";
117 abort();
118 }*/
119
120 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "Global highscore file \"" << filename << "\"";
121 lockedConfig->lock = new QLockFile(filename);
122 lockedConfig->config = new KConfig(filename, KConfig::NoGlobals); // read-only (matt-?)
123
124 // drop the effective gid
125#ifdef __GNUC__
126#warning not portable yet. Unix only. Actually it does not even work there yet.
127#endif
128 int gid = getgid();
129 setregid(gid, gid);
130#else
131 Q_UNUSED(appname);
132#endif
133}
134
136{
137 if (isLocked())
138 return true;
139
140 bool first = true;
141 for (;;) {
142 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "try locking";
143 // lock the highscore file (it should exist)
144 int result = lockedConfig->lock->lock();
145 bool ok = (result == 0);
146 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "locking system-wide highscore file res=" << result << " (ok=" << ok << ")";
147 if (ok) {
149 return true;
150 }
151
152 if (!first) {
154 item.setText(i18nc("@action:button", "Retry"));
155 int res = KMessageBox::warningContinueCancel(widget,
156 i18n("Cannot access the highscore file. Another user is probably currently writing to it."),
157 QString(),
158 item,
160 QStringLiteral("ask_lock_global_highscore_file"));
161 if (res == KMessageBox::Cancel)
162 break;
163 } else {
164#ifdef WIN32
165 Sleep(1000);
166#else
167 sleep(1);
168#endif
169 }
170 first = false;
171 }
172 return false;
173}
174
176{
178
179 if (!d->global) {
181 return;
182 }
183 if (!isLocked())
184 return;
185
186 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "unlocking";
187 lockedConfig->config->sync(); // write config
188 lockedConfig->lock->unlock();
189}
190
195
197{
198 Q_D(const KGameHighscore);
199
200 return (d->global ? lockedConfig->config : static_cast<KConfig *>(KSharedConfig::openConfig().data()));
201}
202
203void KGameHighscore::writeEntry(int entry, const QString &key, const QVariant &value)
204{
205 Q_ASSERT(isLocked());
206 KConfigGroup cg(config(), group());
207 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key);
208 cg.writeEntry(confKey, value);
209}
210
211void KGameHighscore::writeEntry(int entry, const QString &key, int value)
212{
213 Q_ASSERT(isLocked());
214 KConfigGroup cg(config(), group());
215 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key);
216 cg.writeEntry(confKey, value);
217}
218
219void KGameHighscore::writeEntry(int entry, const QString &key, const QString &value)
220{
221 Q_ASSERT(isLocked());
222 KConfigGroup cg(config(), group());
223 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key);
224 cg.writeEntry(confKey, value);
225}
226
227QVariant KGameHighscore::readPropertyEntry(int entry, const QString &key, const QVariant &pDefault) const
228{
229 KConfigGroup cg(config(), group());
230 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key);
231 return cg.readEntry(confKey, pDefault);
232}
233
234QString KGameHighscore::readEntry(int entry, const QString &key, const QString &pDefault) const
235{
236 KConfigGroup cg(config(), group());
237 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key);
238 return cg.readEntry(confKey, pDefault);
239}
240
241int KGameHighscore::readNumEntry(int entry, const QString &key, int pDefault) const
242{
243 KConfigGroup cg(config(), group());
244 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key);
245 return cg.readEntry(confKey, pDefault);
246}
247
248bool KGameHighscore::hasEntry(int entry, const QString &key) const
249{
250 KConfigGroup cg(config(), group());
251 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key);
252 return cg.hasKey(confKey);
253}
254
255QStringList KGameHighscore::readList(const QString &key, int lastEntry) const
256{
257 QStringList list;
258 if (lastEntry > 0) {
259 list.reserve(lastEntry);
260 }
261 for (int i = 1; hasEntry(i, key) && ((lastEntry > 0) ? (i <= lastEntry) : true); i++) {
262 list.append(readEntry(i, key));
263 }
264 return list;
265}
266
267void KGameHighscore::writeList(const QString &key, const QStringList &list)
268{
269 for (int i = 1; i <= list.count(); i++) {
270 writeEntry(i, key, list[i - 1]);
271 }
272}
273
275{
277
278 d->group = group;
279}
280
282{
283 Q_D(const KGameHighscore);
284
285 return d->group;
286}
287
289{
291 QStringList highscoreGroupList;
292 for (QString group : groupList) {
293 if (group.contains(QLatin1String("KHighscore"))) // If it's one of _our_ groups (KHighscore or KHighscore_xxx)
294 {
295 if (group == QLatin1String("KHighscore"))
296 group.remove(QStringLiteral("KHighscore")); // Set to blank
297 else
298 group.remove(QStringLiteral("KHighscore_")); // Remove the KHighscore_ prefix
299 highscoreGroupList << group;
300 }
301 }
302
303 return highscoreGroupList;
304}
305
307{
308 Q_D(const KGameHighscore);
309
310 if (highscoreGroup().isEmpty())
311 return (d->global ? QString() : QStringLiteral(GROUP));
312 return (d->global ? highscoreGroup() : QStringLiteral("%1_%2").arg(QStringLiteral(GROUP), highscoreGroup()));
313}
314
316{
317 return config()->hasGroup(group());
318}
319
320#include "moc_kgamehighscore.cpp"
bool hasGroup(const QString &group) const
bool hasKey(const char *key) const
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QString readEntry(const char *key, const char *aDefault=nullptr) const
QStringList groupList() const override
Class for managing highscore tables.
KConfig * config() const
QStringList groupList() const
Returns a list of group names without the KHighscore_ prexix.
void writeList(const QString &key, const QStringList &list)
Writes a list of entries to the highscore table.
bool isLocked() const
bool hasEntry(int entry, const QString &key) const
void writeAndUnlock()
Effectively write and unlock the system-wide highscore file (.
~KGameHighscore() override
Destructor.
bool lockForWriting(QWidget *widget=nullptr)
Lock the system-wide highscore file for writing (does nothing and return true if the local file is us...
void writeEntry(int entry, const QString &key, const QString &value)
static void init(const char *appname)
This method open the system-wide highscore file using the effective group id of the game executable (...
QString highscoreGroup() const
int readNumEntry(int entry, const QString &key, int pDefault=-1) const
Read a numeric value.
QString readEntry(int entry, const QString &key, const QString &pDefault=QString()) const
Reads an entry from the highscore table.
QString group() const
QStringList readList(const QString &key, int lastEntry=20) const
Reads a list of entries from the highscore table starting at 1 until lastEntry.
bool hasTable() const
You can use this function to indicate whether KGameHighscore created a highscore table before and - i...
void readCurrentConfig()
Read the current state of the highscore file.
QVariant readPropertyEntry(int entry, const QString &key, const QVariant &pDefault) const
Read a QVariant entry.
void setHighscoreGroup(const QString &groupname=QString())
Set the new highscore group.
void setText(const QString &text)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
Q_SCRIPTABLE Q_NOREPLY void abort()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
KGuiItem cont()
KGuiItem cancel()
void append(QList< T > &&value)
qsizetype count() const const
void reserve(qsizetype size)
QString arg(Args &&... args) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromLocal8Bit(QByteArrayView str)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:13:43 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.