00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include "kexthighscore_internal.h"
00021
00022
#include <pwd.h>
00023
#include <sys/types.h>
00024
#include <unistd.h>
00025
00026
#include <qfile.h>
00027
#include <qlayout.h>
00028
#include <qdom.h>
00029
00030
#include <kglobal.h>
00031
#include <kio/netaccess.h>
00032
#include <kio/job.h>
00033
#include <kmessagebox.h>
00034
#include <kmdcodec.h>
00035
#include <kdebug.h>
00036
00037
#include "config.h"
00038
#include "kexthighscore.h"
00039
#include "kexthighscore_gui.h"
00040
00041
00042
namespace KExtHighscore
00043 {
00044
00045
00046
const char ItemContainer::ANONYMOUS[] =
"_";
00047
const char ItemContainer::ANONYMOUS_LABEL[] = I18N_NOOP(
"anonymous");
00048
00049 ItemContainer::ItemContainer()
00050 : _item(0)
00051 {}
00052
00053 ItemContainer::~ItemContainer()
00054 {
00055
delete _item;
00056 }
00057
00058
void ItemContainer::setItem(Item *item)
00059 {
00060
delete _item;
00061 _item = item;
00062 }
00063
00064
QString ItemContainer::entryName()
const
00065
{
00066
if ( _subGroup.isEmpty() )
return _name;
00067
return _name +
"_" + _subGroup;
00068 }
00069
00070
QVariant ItemContainer::read(uint i)
const
00071
{
00072 Q_ASSERT(_item);
00073
00074
QVariant v = _item->defaultValue();
00075
if ( isStored() ) {
00076 internal->hsConfig().setHighscoreGroup(_group);
00077 v = internal->hsConfig().readPropertyEntry(i+1, entryName(), v);
00078 }
00079
return _item->read(i, v);
00080 }
00081
00082
QString ItemContainer::pretty(uint i)
const
00083
{
00084 Q_ASSERT(_item);
00085
return _item->pretty(i, read(i));
00086 }
00087
00088
void ItemContainer::write(uint i,
const QVariant &value)
const
00089
{
00090 Q_ASSERT( isStored() );
00091 Q_ASSERT( internal->hsConfig().isLocked() );
00092 internal->hsConfig().setHighscoreGroup(_group);
00093 internal->hsConfig().writeEntry(i+1, entryName(), value);
00094 }
00095
00096 uint ItemContainer::increment(uint i)
const
00097
{
00098 uint v = read(i).toUInt() + 1;
00099 write(i, v);
00100
return v;
00101 }
00102
00103
00104 ItemArray::ItemArray()
00105 : _group(
""), _subGroup(
"")
00106 {}
00107
00108 ItemArray::~ItemArray()
00109 {
00110
for (uint i=0; i<size(); i++)
delete at(i);
00111 }
00112
00113
int ItemArray::findIndex(
const QString &name)
const
00114
{
00115
for (uint i=0; i<size(); i++)
00116
if ( at(i)->name()==name )
return i;
00117
return -1;
00118 }
00119
00120
const ItemContainer *ItemArray::item(
const QString &name)
const
00121
{
00122
int i = findIndex(name);
00123
if ( i==-1 ) kdError(11002) << k_funcinfo <<
"no item named \"" << name
00124 <<
"\"" << endl;
00125
return at(i);
00126 }
00127
00128 ItemContainer *ItemArray::item(
const QString &name)
00129 {
00130
int i = findIndex(name);
00131
if ( i==-1 ) kdError(11002) << k_funcinfo <<
"no item named \"" << name
00132 <<
"\"" << endl;
00133
return at(i);
00134 }
00135
00136
void ItemArray::setItem(
const QString &name, Item *item)
00137 {
00138
int i = findIndex(name);
00139
if ( i==-1 ) kdError(11002) << k_funcinfo <<
"no item named \"" << name
00140 <<
"\"" << endl;
00141
bool stored = at(i)->isStored();
00142
bool canHaveSubGroup = at(i)->canHaveSubGroup();
00143 _setItem(i, name, item, stored, canHaveSubGroup);
00144 }
00145
00146
void ItemArray::addItem(
const QString &name, Item *item,
00147
bool stored,
bool canHaveSubGroup)
00148 {
00149
if ( findIndex(name)!=-1 )
00150 kdError(11002) <<
"item already exists \"" << name <<
"\"" << endl;
00151 uint i = size();
00152 resize(i+1);
00153 at(i) =
new ItemContainer;
00154 _setItem(i, name, item, stored, canHaveSubGroup);
00155 }
00156
00157
void ItemArray::_setItem(uint i,
const QString &name, Item *item,
00158
bool stored,
bool canHaveSubGroup)
00159 {
00160 at(i)->setItem(item);
00161 at(i)->setName(name);
00162 at(i)->setGroup(stored ? _group : QString::null);
00163 at(i)->setSubGroup(canHaveSubGroup ? _subGroup : QString::null);
00164 }
00165
00166
void ItemArray::setGroup(
const QString &group)
00167 {
00168 Q_ASSERT( !group.isNull() );
00169 _group = group;
00170
for (uint i=0; i<size(); i++)
00171
if ( at(i)->isStored() ) at(i)->setGroup(group);
00172 }
00173
00174
void ItemArray::setSubGroup(
const QString &subGroup)
00175 {
00176 Q_ASSERT( !subGroup.isNull() );
00177 _subGroup = subGroup;
00178
for (uint i=0; i<size(); i++)
00179
if ( at(i)->canHaveSubGroup() ) at(i)->setSubGroup(subGroup);
00180 }
00181
00182
void ItemArray::read(uint k, Score &data)
const
00183
{
00184
for (uint i=0; i<size(); i++) {
00185
if ( !at(i)->isStored() )
continue;
00186 data.setData(at(i)->name(), at(i)->read(k));
00187 }
00188 }
00189
00190
void ItemArray::write(uint k,
const Score &data, uint nb)
const
00191
{
00192
for (uint i=0; i<size(); i++) {
00193
if ( !at(i)->isStored() )
continue;
00194
for (uint j=nb-1; j>k; j--) at(i)->write(j, at(i)->read(j-1));
00195 at(i)->write(k, data.data(at(i)->name()));
00196 }
00197 }
00198
00199
void ItemArray::exportToText(
QTextStream &s)
const
00200
{
00201
for (uint k=0; k<nbEntries()+1; k++) {
00202
for (uint i=0; i<size(); i++) {
00203
const Item *item = at(i)->item();
00204
if ( item->isVisible() ) {
00205
if ( i!=0 ) s <<
'\t';
00206
if ( k==0 ) s << item->label();
00207
else s << at(i)->pretty(k-1);
00208 }
00209 }
00210 s << endl;
00211 }
00212 }
00213
00214
00215
class ScoreNameItem :
public NameItem
00216 {
00217
public:
00218 ScoreNameItem(
const ScoreInfos &score,
const PlayerInfos &infos)
00219 : _score(score), _infos(infos) {}
00220
00221
QString pretty(uint i,
const QVariant &v)
const {
00222 uint
id = _score.item(
"id")->read(i).toUInt();
00223
if (
id==0 )
return NameItem::pretty(i, v);
00224
return _infos.prettyName(
id-1);
00225 }
00226
00227
private:
00228
const ScoreInfos &_score;
00229
const PlayerInfos &_infos;
00230 };
00231
00232
00233 ScoreInfos::ScoreInfos(uint maxNbEntries,
const PlayerInfos &infos)
00234 : _maxNbEntries(maxNbEntries)
00235 {
00236 addItem(
"id",
new Item((uint)0));
00237 addItem(
"rank",
new RankItem,
false);
00238 addItem(
"name",
new ScoreNameItem(*
this, infos));
00239 addItem(
"score", Manager::createItem(Manager::ScoreDefault));
00240 addItem(
"date",
new DateItem);
00241 }
00242
00243 uint ScoreInfos::nbEntries()
const
00244
{
00245 uint i = 0;
00246
for (; i<_maxNbEntries; i++)
00247
if ( item(
"score")->read(i)==item(
"score")->item()->defaultValue() )
00248
break;
00249
return i;
00250 }
00251
00252
00253
const char *HS_ID =
"player id";
00254
const char *HS_REGISTERED_NAME =
"registered name";
00255
const char *HS_KEY =
"player key";
00256
const char *HS_WW_ENABLED =
"ww hs enabled";
00257
00258 PlayerInfos::PlayerInfos()
00259 {
00260 setGroup(
"players");
00261
00262
00263 addItem(
"name",
new NameItem);
00264 Item *it =
new Item((uint)0, i18n(
"Games Count"),Qt::AlignRight);
00265 addItem(
"nb games", it,
true,
true);
00266 it = Manager::createItem(Manager::MeanScoreDefault);
00267 addItem(
"mean score", it,
true,
true);
00268 it = Manager::createItem(Manager::BestScoreDefault);
00269 addItem(
"best score", it,
true,
true);
00270 addItem(
"date",
new DateItem,
true,
true);
00271 it =
new Item(QString::null, i18n(
"Comment"), Qt::AlignLeft);
00272 addItem(
"comment", it);
00273
00274
00275 addItem(
"nb black marks",
new Item((uint)0),
true,
true);
00276 addItem(
"nb lost games",
new Item((uint)0),
true,
true);
00277 addItem(
"nb draw games",
new Item((uint)0),
true,
true);
00278 addItem(
"current trend",
new Item((
int)0),
true,
true);
00279 addItem(
"max lost trend",
new Item((uint)0),
true,
true);
00280 addItem(
"max won trend",
new Item((uint)0),
true,
true);
00281
00282
#ifdef HIGHSCORE_DIRECTORY
00283
struct passwd *pwd = getpwuid(getuid());
00284
QString username = pwd->pw_name;
00285 internal->hsConfig().setHighscoreGroup(
"users");
00286
for (uint i=0; ;i++) {
00287
if ( !internal->hsConfig().hasEntry(i+1,
"username") ) {
00288 _newPlayer =
true;
00289 _id = i;
00290
break;
00291 }
00292
if ( internal->hsConfig().readEntry(i+1,
"username")==username ) {
00293 _newPlayer =
false;
00294 _id = i;
00295
return;
00296 }
00297 }
00298
#endif
00299
internal->hsConfig().lockForWriting();
00300
#ifdef HIGHSCORE_DIRECTORY
00301
internal->hsConfig().writeEntry(_id+1,
"username", username);
00302 item(
"name")->write(_id,
QString(ItemContainer::ANONYMOUS));
00303
#endif
00304
00305 ConfigGroup cg;
00306 _oldLocalPlayer = cg.config()->hasKey(HS_ID);
00307 _oldLocalId = cg.config()->readUnsignedNumEntry(HS_ID);
00308
#ifdef HIGHSCORE_DIRECTORY
00309
if (_oldLocalPlayer) {
00310
00311
QString prefix =
QString(
"%1_").arg(_oldLocalId+1);
00312
QMap<QString, QString> entries =
00313 cg.config()->entryMap(
"KHighscore_players");
00314
QMap<QString, QString>::const_iterator it;
00315
for (it=entries.begin(); it!=entries.end(); ++it) {
00316
QString key = it.key();
00317
if ( key.find(prefix)==0 ) {
00318
QString name = key.right(key.length()-prefix.length());
00319
if ( name!=
"name" || !isNameUsed(it.data()) )
00320 internal->hsConfig().writeEntry(_id+1, name, it.data());
00321 }
00322 }
00323 }
00324
#else
00325
_newPlayer = !_oldLocalPlayer;
00326
if (_oldLocalPlayer) _id = _oldLocalId;
00327
else {
00328 _id = nbEntries();
00329 cg.config()->writeEntry(HS_ID, _id);
00330 item(
"name")->write(_id,
QString(ItemContainer::ANONYMOUS));
00331 }
00332
#endif
00333
internal->hsConfig().writeAndUnlock();
00334 }
00335
00336
void PlayerInfos::createHistoItems(
const QMemArray<uint> &scores,
bool bound)
00337 {
00338 Q_ASSERT( _histogram.size()==0 );
00339 _bound = bound;
00340 _histogram = scores;
00341
for (uint i=1; i<histoSize(); i++)
00342 addItem(histoName(i),
new Item((uint)0),
true,
true);
00343 }
00344
00345
bool PlayerInfos::isAnonymous()
const
00346
{
00347
return ( name()==ItemContainer::ANONYMOUS );
00348 }
00349
00350 uint PlayerInfos::nbEntries()
const
00351
{
00352 internal->hsConfig().setHighscoreGroup(
"players");
00353
QStringList list = internal->hsConfig().readList(
"name", -1);
00354
return list.count();
00355 }
00356
00357
QString PlayerInfos::key()
const
00358
{
00359 ConfigGroup cg;
00360
return cg.config()->readEntry(HS_KEY, QString::null);
00361 }
00362
00363
bool PlayerInfos::isWWEnabled()
const
00364
{
00365 ConfigGroup cg;
00366
return cg.config()->readBoolEntry(HS_WW_ENABLED,
false);
00367 }
00368
00369
QString PlayerInfos::histoName(uint i)
const
00370
{
00371
const QMemArray<uint> &sh = _histogram;
00372 Q_ASSERT( i<sh.size() || (_bound || i==sh.size()) );
00373
if ( i==sh.size() )
00374
return QString(
"nb scores greater than %1").arg(sh[sh.size()-1]);
00375
return QString(
"nb scores less than %1").arg(sh[i]);
00376 }
00377
00378 uint PlayerInfos::histoSize()
const
00379
{
00380
return _histogram.size() + (_bound ? 0 : 1);
00381 }
00382
00383
void PlayerInfos::submitScore(
const Score &score)
const
00384
{
00385
00386 uint nbGames = item(
"nb games")->increment(_id);
00387
switch (score.type()) {
00388
case Lost:
00389 item(
"nb lost games")->increment(_id);
00390
break;
00391
case Won:
break;
00392
case Draw:
00393 item(
"nb draw games")->increment(_id);
00394
break;
00395 };
00396
00397
00398
if ( score.type()==Won ) {
00399 uint nbWonGames = nbGames - item(
"nb lost games")->read(_id).toUInt()
00400 - item(
"nb draw games")->read(_id).toUInt()
00401 - item(
"nb black marks")->read(_id).toUInt();
00402
double mean = (nbWonGames==1 ? 0.0
00403 : item(
"mean score")->read(_id).toDouble());
00404 mean += (double(score.score()) - mean) / nbWonGames;
00405 item(
"mean score")->write(_id, mean);
00406 }
00407
00408
00409 Score best = score;
00410 best.setScore( item(
"best score")->read(_id).toUInt() );
00411
if ( best<score ) {
00412 item(
"best score")->write(_id, score.score());
00413 item(
"date")->write(_id, score.data(
"date").toDateTime());
00414 }
00415
00416
00417
int current = item(
"current trend")->read(_id).toInt();
00418
switch (score.type()) {
00419
case Won: {
00420
if ( current<0 ) current = 0;
00421 current++;
00422 uint won = item(
"max won trend")->read(_id).toUInt();
00423
if ( (uint)current>won ) item(
"max won trend")->write(_id, current);
00424
break;
00425 }
00426
case Lost: {
00427
if ( current>0 ) current = 0;
00428 current--;
00429 uint lost = item(
"max lost trend")->read(_id).toUInt();
00430 uint clost = -current;
00431
if ( clost>lost ) item(
"max lost trend")->write(_id, clost);
00432
break;
00433 }
00434
case Draw:
00435 current = 0;
00436
break;
00437 }
00438 item(
"current trend")->write(_id, current);
00439
00440
00441
if ( score.type()==Won ) {
00442
const QMemArray<uint> &sh = _histogram;
00443
for (uint i=1; i<histoSize(); i++)
00444
if ( i==sh.size() || score.score()<sh[i] ) {
00445 item(histoName(i))->increment(_id);
00446
break;
00447 }
00448 }
00449 }
00450
00451
bool PlayerInfos::isNameUsed(
const QString &newName)
const
00452
{
00453
if ( newName==name() )
return false;
00454
for (uint i=0; i<nbEntries(); i++)
00455
if ( newName==item(
"name")->read(i).toString() )
return true;
00456
if ( newName==i18n(ItemContainer::ANONYMOUS_LABEL) )
return true;
00457
return false;
00458 }
00459
00460
void PlayerInfos::modifyName(
const QString &newName)
const
00461
{
00462 item(
"name")->write(_id, newName);
00463 }
00464
00465
void PlayerInfos::modifySettings(
const QString &newName,
00466
const QString &comment,
bool WWEnabled,
00467
const QString &newKey)
const
00468
{
00469 modifyName(newName);
00470 item(
"comment")->write(_id, comment);
00471 ConfigGroup cg;
00472 cg.config()->writeEntry(HS_WW_ENABLED, WWEnabled);
00473
if ( !newKey.isEmpty() ) cg.config()->writeEntry(HS_KEY, newKey);
00474
if (WWEnabled) cg.config()->writeEntry(HS_REGISTERED_NAME, newName);
00475 }
00476
00477
QString PlayerInfos::registeredName()
const
00478
{
00479 ConfigGroup cg;
00480
return cg.config()->readEntry(HS_REGISTERED_NAME, QString::null);
00481 }
00482
00483
void PlayerInfos::removeKey()
00484 {
00485 ConfigGroup cg;
00486
00487
00488 uint i = 0;
00489
QString str =
"%1 old #%2";
00490
QString sk;
00491
do {
00492 i++;
00493 sk = str.arg(HS_KEY).arg(i);
00494 }
while ( !cg.config()->readEntry(sk, QString::null).isEmpty() );
00495 cg.config()->writeEntry(sk, key());
00496 cg.config()->writeEntry(str.arg(HS_REGISTERED_NAME).arg(i),
00497 registeredName());
00498
00499
00500 cg.config()->deleteEntry(HS_KEY);
00501 cg.config()->deleteEntry(HS_REGISTERED_NAME);
00502 cg.config()->writeEntry(HS_WW_ENABLED,
false);
00503 }
00504
00505
00506 ManagerPrivate::ManagerPrivate(uint nbGameTypes, Manager &m)
00507 : manager(m), showStatistics(false), showDrawGames(false),
00508 trackLostGames(false), trackDrawGames(false),
00509 showMode(Manager::ShowForHigherScore),
00510 _first(true), _nbGameTypes(nbGameTypes), _gameType(0)
00511 {}
00512
00513
void ManagerPrivate::init(uint maxNbEntries)
00514 {
00515 _hsConfig =
new KHighscore(
false, 0);
00516 _playerInfos =
new PlayerInfos;
00517 _scoreInfos =
new ScoreInfos(maxNbEntries, *_playerInfos);
00518 }
00519
00520 ManagerPrivate::~ManagerPrivate()
00521 {
00522
delete _scoreInfos;
00523
delete _playerInfos;
00524
delete _hsConfig;
00525 }
00526
00527 KURL ManagerPrivate::queryURL(QueryType type,
const QString &newName)
const
00528
{
00529 KURL url = serverURL;
00530
QString nameItem =
"nickname";
00531
QString name = _playerInfos->registeredName();
00532
bool withVersion =
true;
00533
bool key =
false;
00534
bool level =
false;
00535
00536
switch (type) {
00537
case Submit:
00538 url.addPath(
"submit.php");
00539 level =
true;
00540 key =
true;
00541
break;
00542
case Register:
00543 url.addPath(
"register.php");
00544 name = newName;
00545
break;
00546
case Change:
00547 url.addPath(
"change.php");
00548 key =
true;
00549
if ( newName!=name )
00550 Manager::addToQueryURL(url,
"new_nickname", newName);
00551
break;
00552
case Players:
00553 url.addPath(
"players.php");
00554 nameItem =
"highlight";
00555 withVersion =
false;
00556
break;
00557
case Scores:
00558 url.addPath(
"highscores.php");
00559 withVersion =
false;
00560
if ( _nbGameTypes>1 ) level =
true;
00561
break;
00562 }
00563
00564
if (withVersion) Manager::addToQueryURL(url,
"version", version);
00565
if ( !name.isEmpty() ) Manager::addToQueryURL(url, nameItem, name);
00566
if (key) Manager::addToQueryURL(url,
"key", _playerInfos->key());
00567
if (level) {
00568
QString label = manager.gameTypeLabel(_gameType, Manager::WW);
00569
if ( !label.isEmpty() ) Manager::addToQueryURL(url,
"level", label);
00570 }
00571
00572
return url;
00573 }
00574
00575
00576
const char *DUMMY_STRINGS[] = {
00577 I18N_NOOP(
"Undefined error."),
00578 I18N_NOOP(
"Missing argument(s)."),
00579 I18N_NOOP(
"Invalid argument(s)."),
00580
00581 I18N_NOOP(
"Unable to connect to MySQL server."),
00582 I18N_NOOP(
"Unable to select database."),
00583 I18N_NOOP(
"Error on database query."),
00584 I18N_NOOP(
"Error on database insert."),
00585
00586 I18N_NOOP(
"Nickname already registered."),
00587 I18N_NOOP(
"Nickname not registered."),
00588 I18N_NOOP(
"Invalid key."),
00589 I18N_NOOP(
"Invalid submit key."),
00590
00591 I18N_NOOP(
"Invalid level."),
00592 I18N_NOOP(
"Invalid score.")
00593 };
00594
00595
const char *UNABLE_TO_CONTACT =
00596 I18N_NOOP(
"Unable to contact world-wide highscore server");
00597
00598
bool ManagerPrivate::doQuery(
const KURL &url,
QWidget *parent,
00599
QDomNamedNodeMap *map)
00600 {
00601 KIO::http_update_cache(url,
true, 0);
00602
00603
QString tmpFile;
00604
if ( !KIO::NetAccess::download(url, tmpFile, parent) ) {
00605
QString details = i18n(
"Server URL: %1").arg(url.host());
00606 KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
00607
return false;
00608 }
00609
00610
QFile file(tmpFile);
00611
if ( !file.open(IO_ReadOnly) ) {
00612 KIO::NetAccess::removeTempFile(tmpFile);
00613
QString details = i18n(
"Unable to open temporary file.");
00614 KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
00615
return false;
00616 }
00617
00618
QTextStream t(&file);
00619
QString content = t.read().stripWhiteSpace();
00620 file.close();
00621 KIO::NetAccess::removeTempFile(tmpFile);
00622
00623
QDomDocument doc;
00624
if ( doc.setContent(content) ) {
00625
QDomElement root = doc.documentElement();
00626
QDomElement element = root.firstChild().toElement();
00627
if ( element.tagName()==
"success" ) {
00628
if (map) *map = element.attributes();
00629
return true;
00630 }
00631
if ( element.tagName()==
"error" ) {
00632
QDomAttr attr = element.attributes().namedItem(
"label").toAttr();
00633
if ( !attr.isNull() ) {
00634
QString msg = i18n(attr.value().latin1());
00635
QString caption = i18n(
"Message from world-wide highscores "
00636
"server");
00637 KMessageBox::sorry(parent, msg, caption);
00638
return false;
00639 }
00640 }
00641 }
00642
QString msg = i18n(
"Invalid answer from world-wide highscores server.");
00643
QString details = i18n(
"Raw message: %1").arg(content);
00644 KMessageBox::detailedSorry(parent, msg, details);
00645
return false;
00646 }
00647
00648
bool ManagerPrivate::getFromQuery(
const QDomNamedNodeMap &map,
00649
const QString &name,
QString &value,
00650
QWidget *parent)
00651 {
00652
QDomAttr attr = map.namedItem(name).toAttr();
00653
if ( attr.isNull() ) {
00654 KMessageBox::sorry(parent,
00655 i18n(
"Invalid answer from world-wide "
00656
"highscores server (missing item: %1).").arg(name));
00657
return false;
00658 }
00659 value = attr.value();
00660
return true;
00661 }
00662
00663 Score ManagerPrivate::readScore(uint i)
const
00664
{
00665 Score score(Won);
00666 _scoreInfos->read(i, score);
00667
return score;
00668 }
00669
00670
int ManagerPrivate::rank(
const Score &score)
const
00671
{
00672 uint nb = _scoreInfos->nbEntries();
00673 uint i = 0;
00674
for (; i<nb; i++)
00675
if ( readScore(i)<score )
break;
00676
return (i<_scoreInfos->maxNbEntries() ? (
int)i : -1);
00677 }
00678
00679
bool ManagerPrivate::modifySettings(
const QString &newName,
00680
const QString &comment,
bool WWEnabled,
00681
QWidget *widget)
00682 {
00683
QString newKey;
00684
bool newPlayer =
false;
00685
00686
if (WWEnabled) {
00687 newPlayer = _playerInfos->key().isEmpty()
00688 || _playerInfos->registeredName().isEmpty();
00689 KURL url = queryURL((newPlayer ? Register : Change), newName);
00690 Manager::addToQueryURL(url,
"comment", comment);
00691
00692
QDomNamedNodeMap map;
00693
bool ok = doQuery(url, widget, &map);
00694
if ( !ok || (newPlayer && !getFromQuery(map,
"key", newKey, widget)) )
00695
return false;
00696 }
00697
00698
bool ok = _hsConfig->lockForWriting(widget);
00699
if (ok) {
00700
00701
00702
00703 ok = ( !_playerInfos->isNameUsed(newName) );
00704
if (ok)
00705 _playerInfos->modifySettings(newName, comment, WWEnabled, newKey);
00706 _hsConfig->writeAndUnlock();
00707 }
00708
return ok;
00709 }
00710
00711
void ManagerPrivate::convertToGlobal()
00712 {
00713
00714
KHighscore *tmp = _hsConfig;
00715 _hsConfig =
new KHighscore(
true, 0);
00716
QValueVector<Score> scores(_scoreInfos->nbEntries());
00717
for (uint i=0; i<scores.count(); i++)
00718 scores[i] = readScore(i);
00719
00720
00721
delete _hsConfig;
00722 _hsConfig = tmp;
00723 _hsConfig->
lockForWriting();
00724
for (uint i=0; i<scores.count(); i++)
00725
if ( scores[i].data(
"id").toUInt()==_playerInfos->oldLocalId()+1 )
00726 submitLocal(scores[i]);
00727 _hsConfig->
writeAndUnlock();
00728 }
00729
00730
void ManagerPrivate::setGameType(uint type)
00731 {
00732
if (_first) {
00733 _first =
false;
00734
if ( _playerInfos->isNewPlayer() ) {
00735
00736
for (uint i=0; i<_nbGameTypes; i++) {
00737 setGameType(i);
00738 manager.convertLegacy(i);
00739 }
00740
00741
#ifdef HIGHSCORE_DIRECTORY
00742
if ( _playerInfos->isOldLocalPlayer() ) {
00743
00744
for (uint i=0; i<_nbGameTypes; i++) {
00745 setGameType(i);
00746 convertToGlobal();
00747 }
00748 }
00749
#endif
00750
}
00751 }
00752
00753 Q_ASSERT( type<_nbGameTypes );
00754 _gameType = kMin(type, _nbGameTypes-1);
00755
QString str =
"scores";
00756
QString lab = manager.gameTypeLabel(_gameType, Manager::Standard);
00757
if ( !lab.isEmpty() ) {
00758 _playerInfos->setSubGroup(lab);
00759 str +=
"_" + lab;
00760 }
00761 _scoreInfos->setGroup(str);
00762 }
00763
00764
void ManagerPrivate::checkFirst()
00765 {
00766
if (_first) setGameType(0);
00767 }
00768
00769
int ManagerPrivate::submitScore(
const Score &ascore,
00770
QWidget *widget,
bool askIfAnonymous)
00771 {
00772 checkFirst();
00773
00774 Score score = ascore;
00775 score.setData(
"id", _playerInfos->id() + 1);
00776 score.setData(
"date", QDateTime::currentDateTime());
00777
00778
00779
const char *dontAskAgainName =
"highscore_ask_name_dialog";
00780
QString newName;
00781 KMessageBox::ButtonCode dummy;
00782
if ( score.type()==Won && askIfAnonymous && _playerInfos->isAnonymous()
00783 && KMessageBox::shouldBeShownYesNo(dontAskAgainName, dummy) ) {
00784 AskNameDialog d(widget);
00785
if ( d.exec()==QDialog::Accepted ) newName = d.name();
00786
if ( d.dontAskAgain() )
00787 KMessageBox::saveDontShowAgainYesNo(dontAskAgainName,
00788 KMessageBox::No);
00789 }
00790
00791
int rank = -1;
00792
if ( _hsConfig->lockForWriting(widget) ) {
00793
00794
if ( !newName.isEmpty() && !_playerInfos->isNameUsed(newName) )
00795 _playerInfos->modifyName(newName);
00796
00797
00798 _playerInfos->submitScore(score);
00799
if ( score.type()==Won ) rank = submitLocal(score);
00800 _hsConfig->writeAndUnlock();
00801 }
00802
00803
if ( _playerInfos->isWWEnabled() )
00804 submitWorldWide(score, widget);
00805
00806
return rank;
00807 }
00808
00809
int ManagerPrivate::submitLocal(
const Score &score)
00810 {
00811
int r = rank(score);
00812
if ( r!=-1 ) {
00813 uint nb = _scoreInfos->nbEntries();
00814
if ( nb<_scoreInfos->maxNbEntries() ) nb++;
00815 _scoreInfos->write(r, score, nb);
00816 }
00817
return r;
00818 }
00819
00820
bool ManagerPrivate::submitWorldWide(
const Score &score,
00821
QWidget *widget)
const
00822
{
00823
if ( score.type()==Lost && !trackLostGames )
return true;
00824
if ( score.type()==Draw && !trackDrawGames )
return true;
00825
00826 KURL url = queryURL(Submit);
00827 manager.additionalQueryItems(url, score);
00828
int s = (score.type()==Won ? score.score() : (int)score.type());
00829
QString str = QString::number(s);
00830 Manager::addToQueryURL(url,
"score", str);
00831 KMD5 context(
QString(_playerInfos->registeredName() + str).latin1());
00832 Manager::addToQueryURL(url,
"check", context.hexDigest());
00833
00834
return doQuery(url, widget);
00835 }
00836
00837
void ManagerPrivate::exportHighscores(
QTextStream &s)
00838 {
00839 uint tmp = _gameType;
00840
00841
for (uint i=0; i<_nbGameTypes; i++) {
00842 setGameType(i);
00843
if ( _nbGameTypes>1 ) {
00844
if ( i!=0 ) s << endl;
00845 s <<
"--------------------------------" << endl;
00846 s <<
"Game type: "
00847 << manager.gameTypeLabel(_gameType, Manager::I18N)
00848 << endl;
00849 s << endl;
00850 }
00851 s <<
"Players list:" << endl;
00852 _playerInfos->exportToText(s);
00853 s << endl;
00854 s <<
"Highscores list:" << endl;
00855 _scoreInfos->exportToText(s);
00856 }
00857
00858 setGameType(tmp);
00859 }
00860
00861 }