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("current trend", new Item((int)0), true, true);
00278 addItem("max lost trend", new Item((uint)0), true, true);
00279 addItem("max won trend", new Item((uint)0), true, true);
00280
00281 #ifdef HIGHSCORE_DIRECTORY
00282 struct passwd *pwd = getpwuid(getuid());
00283 QString username = pwd->pw_name;
00284 internal->hsConfig().setHighscoreGroup("users");
00285 for (uint i=0; ;i++) {
00286 if ( !internal->hsConfig().hasEntry(i+1, "username") ) {
00287 _newPlayer = true;
00288 _id = i;
00289 break;
00290 }
00291 if ( internal->hsConfig().readEntry(i+1, "username")==username ) {
00292 _newPlayer = false;
00293 _id = i;
00294 return;
00295 }
00296 }
00297 #endif
00298 internal->hsConfig().lockForWriting();
00299 #ifdef HIGHSCORE_DIRECTORY
00300 internal->hsConfig().writeEntry(_id+1, "username", username);
00301 item("name")->write(_id, QString(ItemContainer::ANONYMOUS));
00302 #endif
00303
00304 ConfigGroup cg;
00305 _oldLocalPlayer = cg.config()->hasKey(HS_ID);
00306 _oldLocalId = cg.config()->readUnsignedNumEntry(HS_ID);
00307 #ifdef HIGHSCORE_DIRECTORY
00308 if (_oldLocalPlayer) {
00309
00310 QString prefix = QString("%1_").arg(_oldLocalId+1);
00311 QMap<QString, QString> entries =
00312 cg.config()->entryMap("KHighscore_players");
00313 QMap<QString, QString>::const_iterator it;
00314 for (it=entries.begin(); it!=entries.end(); ++it) {
00315 QString key = it.key();
00316 if ( key.find(prefix)==0 ) {
00317 QString name = key.right(key.length()-prefix.length());
00318 if ( name!="name" || !isNameUsed(it.data()) )
00319 internal->hsConfig().writeEntry(_id+1, name, it.data());
00320 }
00321 }
00322 }
00323 #else
00324 _newPlayer = !_oldLocalPlayer;
00325 if (_oldLocalPlayer) _id = _oldLocalId;
00326 else {
00327 _id = nbEntries();
00328 cg.config()->writeEntry(HS_ID, _id);
00329 item("name")->write(_id, QString(ItemContainer::ANONYMOUS));
00330 }
00331 #endif
00332 internal->hsConfig().writeAndUnlock();
00333 }
00334
00335 void PlayerInfos::createHistoItems(const QMemArray<uint> &scores, bool bound)
00336 {
00337 Q_ASSERT( _histogram.size()==0 );
00338 _bound = bound;
00339 _histogram = scores;
00340 for (uint i=1; i<histoSize(); i++)
00341 addItem(histoName(i), new Item((uint)0), true, true);
00342 }
00343
00344 bool PlayerInfos::isAnonymous() const
00345 {
00346 return ( name()==ItemContainer::ANONYMOUS );
00347 }
00348
00349 uint PlayerInfos::nbEntries() const
00350 {
00351 internal->hsConfig().setHighscoreGroup("players");
00352 QStringList list = internal->hsConfig().readList("name", -1);
00353 return list.count();
00354 }
00355
00356 QString PlayerInfos::key() const
00357 {
00358 ConfigGroup cg;
00359 return cg.config()->readEntry(HS_KEY, QString::null);
00360 }
00361
00362 bool PlayerInfos::isWWEnabled() const
00363 {
00364 ConfigGroup cg;
00365 return cg.config()->readBoolEntry(HS_WW_ENABLED, false);
00366 }
00367
00368 QString PlayerInfos::histoName(uint i) const
00369 {
00370 const QMemArray<uint> &sh = _histogram;
00371 Q_ASSERT( i<sh.size() || (_bound || i==sh.size()) );
00372 if ( i==sh.size() )
00373 return QString("nb scores greater than %1").arg(sh[sh.size()-1]);
00374 return QString("nb scores less than %1").arg(sh[i]);
00375 }
00376
00377 uint PlayerInfos::histoSize() const
00378 {
00379 return _histogram.size() + (_bound ? 0 : 1);
00380 }
00381
00382 void PlayerInfos::submitScore(const Score &score) const
00383 {
00384
00385 uint nbGames = item("nb games")->increment(_id);
00386 bool lost = true;
00387 switch (score.type()) {
00388 case Lost:
00389 item("nb lost games")->increment(_id);
00390 break;
00391 case Won:
00392 lost = false;
00393 break;
00394 };
00395
00396
00397 if ( !lost ) {
00398 uint nbWonGames = nbGames - item("nb lost games")->read(_id).toUInt()
00399 - item("nb black marks")->read(_id).toUInt();
00400 double mean = (nbWonGames==1 ? 0.0
00401 : item("mean score")->read(_id).toDouble());
00402 mean += (double(score.score()) - mean) / nbWonGames;
00403 item("mean score")->write(_id, mean);
00404 }
00405
00406
00407 Score best = score;
00408 best.setScore( item("best score")->read(_id).toUInt() );
00409 if ( best<score ) {
00410 item("best score")->write(_id, score.score());
00411 item("date")->write(_id, score.data("date").toDateTime());
00412 }
00413
00414
00415 int current = item("current trend")->read(_id).toInt();
00416 if (lost) {
00417 if ( current>0 ) current = 0;
00418 current--;
00419 uint lost = item("max lost trend")->read(_id).toUInt();
00420 uint clost = -current;
00421 if ( clost>lost ) item("max lost trend")->write(_id, clost);
00422 } else {
00423 if ( current<0 ) current = 0;
00424 current++;
00425 uint won = item("max won trend")->read(_id).toUInt();
00426 if ( (uint)current>won ) item("max won trend")->write(_id, current);
00427 }
00428 item("current trend")->write(_id, current);
00429
00430
00431 if ( !lost ) {
00432 const QMemArray<uint> &sh = _histogram;
00433 for (uint i=1; i<histoSize(); i++)
00434 if ( i==sh.size() || score.score()<sh[i] ) {
00435 item(histoName(i))->increment(_id);
00436 break;
00437 }
00438 }
00439 }
00440
00441 bool PlayerInfos::isNameUsed(const QString &newName) const
00442 {
00443 if ( newName==name() ) return false;
00444 for (uint i=0; i<nbEntries(); i++)
00445 if ( newName==item("name")->read(i).toString() ) return true;
00446 if ( newName==i18n(ItemContainer::ANONYMOUS_LABEL) ) return true;
00447 return false;
00448 }
00449
00450 void PlayerInfos::modifyName(const QString &newName) const
00451 {
00452 item("name")->write(_id, newName);
00453 }
00454
00455 void PlayerInfos::modifySettings(const QString &newName,
00456 const QString &comment, bool WWEnabled,
00457 const QString &newKey) const
00458 {
00459 modifyName(newName);
00460 item("comment")->write(_id, comment);
00461 ConfigGroup cg;
00462 cg.config()->writeEntry(HS_WW_ENABLED, WWEnabled);
00463 if ( !newKey.isEmpty() ) cg.config()->writeEntry(HS_KEY, newKey);
00464 if (WWEnabled) cg.config()->writeEntry(HS_REGISTERED_NAME, newName);
00465 }
00466
00467 QString PlayerInfos::registeredName() const
00468 {
00469 ConfigGroup cg;
00470 return cg.config()->readEntry(HS_REGISTERED_NAME, QString::null);
00471 }
00472
00473 void PlayerInfos::removeKey()
00474 {
00475 ConfigGroup cg;
00476
00477
00478 uint i = 0;
00479 QString str = "%1 old #%2";
00480 QString sk;
00481 do {
00482 i++;
00483 sk = str.arg(HS_KEY).arg(i);
00484 } while ( !cg.config()->readEntry(sk, QString::null).isEmpty() );
00485 cg.config()->writeEntry(sk, key());
00486 cg.config()->writeEntry(str.arg(HS_REGISTERED_NAME).arg(i),
00487 registeredName());
00488
00489
00490 cg.config()->deleteEntry(HS_KEY);
00491 cg.config()->deleteEntry(HS_REGISTERED_NAME);
00492 cg.config()->writeEntry(HS_WW_ENABLED, false);
00493 }
00494
00495
00496 ManagerPrivate::ManagerPrivate(uint nbGameTypes, Manager &m)
00497 : manager(m), showStatistics(false), trackLostGames(false),
00498 showMode(Manager::ShowForHigherScore),
00499 _first(true), _nbGameTypes(nbGameTypes), _gameType(0)
00500 {}
00501
00502 void ManagerPrivate::init(uint maxNbEntries)
00503 {
00504 _hsConfig = new KHighscore(false, 0);
00505 _playerInfos = new PlayerInfos;
00506 _scoreInfos = new ScoreInfos(maxNbEntries, *_playerInfos);
00507 }
00508
00509 ManagerPrivate::~ManagerPrivate()
00510 {
00511 delete _scoreInfos;
00512 delete _playerInfos;
00513 delete _hsConfig;
00514 }
00515
00516 KURL ManagerPrivate::queryURL(QueryType type, const QString &newName) const
00517 {
00518 KURL url = serverURL;
00519 QString nameItem = "nickname";
00520 QString name = _playerInfos->registeredName();
00521 bool withVersion = true;
00522 bool key = false;
00523 bool level = false;
00524
00525 switch (type) {
00526 case Submit:
00527 url.addPath("submit.php");
00528 level = true;
00529 key = true;
00530 break;
00531 case Register:
00532 url.addPath("register.php");
00533 name = newName;
00534 break;
00535 case Change:
00536 url.addPath("change.php");
00537 key = true;
00538 if ( newName!=name )
00539 Manager::addToQueryURL(url, "new_nickname", newName);
00540 break;
00541 case Players:
00542 url.addPath("players.php");
00543 nameItem = "highlight";
00544 withVersion = false;
00545 break;
00546 case Scores:
00547 url.addPath("highscores.php");
00548 withVersion = false;
00549 if ( _nbGameTypes>1 ) level = true;
00550 break;
00551 }
00552
00553 if (withVersion) Manager::addToQueryURL(url, "version", version);
00554 if ( !name.isEmpty() ) Manager::addToQueryURL(url, nameItem, name);
00555 if (key) Manager::addToQueryURL(url, "key", _playerInfos->key());
00556 if (level) {
00557 QString label = manager.gameTypeLabel(_gameType, Manager::WW);
00558 if ( !label.isEmpty() ) Manager::addToQueryURL(url, "level", label);
00559 }
00560
00561 return url;
00562 }
00563
00564
00565 const char *DUMMY_STRINGS[] = {
00566 I18N_NOOP("Undefined error."),
00567 I18N_NOOP("Missing argument(s)."),
00568 I18N_NOOP("Invalid argument(s)."),
00569
00570 I18N_NOOP("Unable to connect to MySQL server."),
00571 I18N_NOOP("Unable to select database."),
00572 I18N_NOOP("Error on database query."),
00573 I18N_NOOP("Error on database insert."),
00574
00575 I18N_NOOP("Nickname already registered."),
00576 I18N_NOOP("Nickname not registered."),
00577 I18N_NOOP("Invalid key."),
00578 I18N_NOOP("Invalid submit key."),
00579
00580 I18N_NOOP("Invalid level."),
00581 I18N_NOOP("Invalid score.")
00582 };
00583
00584 const char *UNABLE_TO_CONTACT =
00585 I18N_NOOP("Unable to contact world-wide highscore server");
00586
00587 bool ManagerPrivate::doQuery(const KURL &url, QWidget *parent,
00588 QDomNamedNodeMap *map)
00589 {
00590 KIO::http_update_cache(url, true, 0);
00591
00592 QString tmpFile;
00593 if ( !KIO::NetAccess::download(url, tmpFile) ) {
00594 QString details = i18n("Server URL: %1").arg(url.host());
00595 KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
00596 return false;
00597 }
00598
00599 QFile file(tmpFile);
00600 if ( !file.open(IO_ReadOnly) ) {
00601 KIO::NetAccess::removeTempFile(tmpFile);
00602 QString details = i18n("Unable to open temporary file.");
00603 KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
00604 return false;
00605 }
00606
00607 QTextStream t(&file);
00608 QString content = t.read().stripWhiteSpace();
00609 file.close();
00610 KIO::NetAccess::removeTempFile(tmpFile);
00611
00612 QDomDocument doc;
00613 if ( doc.setContent(content) ) {
00614 QDomElement root = doc.documentElement();
00615 QDomElement element = root.firstChild().toElement();
00616 if ( element.tagName()=="success" ) {
00617 if (map) *map = element.attributes();
00618 return true;
00619 }
00620 if ( element.tagName()=="error" ) {
00621 QDomAttr attr = element.attributes().namedItem("label").toAttr();
00622 if ( !attr.isNull() ) {
00623 QString msg = i18n(attr.value().latin1());
00624 QString caption = i18n("Message from world-wide highscores "
00625 "server");
00626 KMessageBox::sorry(parent, msg, caption);
00627 return false;
00628 }
00629 }
00630 }
00631 QString msg = i18n("Invalid answer from world-wide highscores server.");
00632 QString details = i18n("Raw message: %1").arg(content);
00633 KMessageBox::detailedSorry(parent, msg, details);
00634 return false;
00635 }
00636
00637 bool ManagerPrivate::getFromQuery(const QDomNamedNodeMap &map,
00638 const QString &name, QString &value,
00639 QWidget *parent)
00640 {
00641 QDomAttr attr = map.namedItem(name).toAttr();
00642 if ( attr.isNull() ) {
00643 KMessageBox::sorry(parent,
00644 i18n("Invalid answer from world-wide "
00645 "highscores server (missing item: %1).").arg(name));
00646 return false;
00647 }
00648 value = attr.value();
00649 return true;
00650 }
00651
00652 Score ManagerPrivate::readScore(uint i) const
00653 {
00654 Score score(Won);
00655 _scoreInfos->read(i, score);
00656 return score;
00657 }
00658
00659 int ManagerPrivate::rank(const Score &score) const
00660 {
00661 uint nb = _scoreInfos->nbEntries();
00662 uint i = 0;
00663 for (; i<nb; i++)
00664 if ( readScore(i)<score ) break;
00665 return (i<_scoreInfos->maxNbEntries() ? (int)i : -1);
00666 }
00667
00668 bool ManagerPrivate::modifySettings(const QString &newName,
00669 const QString &comment, bool WWEnabled,
00670 QWidget *widget)
00671 {
00672 QString newKey;
00673 bool newPlayer = false;
00674
00675 if (WWEnabled) {
00676 newPlayer = _playerInfos->key().isEmpty()
00677 || _playerInfos->registeredName().isEmpty();
00678 KURL url = queryURL((newPlayer ? Register : Change), newName);
00679 Manager::addToQueryURL(url, "comment", comment);
00680
00681 QDomNamedNodeMap map;
00682 bool ok = doQuery(url, widget, &map);
00683 if ( !ok || (newPlayer && !getFromQuery(map, "key", newKey, widget)) )
00684 return false;
00685 }
00686
00687 bool ok = _hsConfig->lockForWriting(widget);
00688 if (ok) {
00689
00690
00691
00692 ok = ( !_playerInfos->isNameUsed(newName) );
00693 if (ok)
00694 _playerInfos->modifySettings(newName, comment, WWEnabled, newKey);
00695 _hsConfig->writeAndUnlock();
00696 }
00697 return ok;
00698 }
00699
00700 void ManagerPrivate::convertToGlobal()
00701 {
00702
00703 KHighscore *tmp = _hsConfig;
00704 _hsConfig = new KHighscore(true, 0);
00705 QValueVector<Score> scores(_scoreInfos->nbEntries());
00706 for (uint i=0; i<scores.count(); i++)
00707 scores[i] = readScore(i);
00708
00709
00710 delete _hsConfig;
00711 _hsConfig = tmp;
00712 _hsConfig->lockForWriting();
00713 for (uint i=0; i<scores.count(); i++)
00714 if ( scores[i].data("id").toUInt()==_playerInfos->oldLocalId()+1 )
00715 submitLocal(scores[i]);
00716 _hsConfig->writeAndUnlock();
00717 }
00718
00719 void ManagerPrivate::setGameType(uint type)
00720 {
00721 if (_first) {
00722 _first = false;
00723 if ( _playerInfos->isNewPlayer() ) {
00724
00725 for (uint i=0; i<_nbGameTypes; i++) {
00726 setGameType(i);
00727 manager.convertLegacy(i);
00728 }
00729
00730 #ifdef HIGHSCORE_DIRECTORY
00731 if ( _playerInfos->isOldLocalPlayer() ) {
00732
00733 for (uint i=0; i<_nbGameTypes; i++) {
00734 setGameType(i);
00735 convertToGlobal();
00736 }
00737 }
00738 #endif
00739 }
00740 }
00741
00742 Q_ASSERT( type<_nbGameTypes );
00743 _gameType = kMin(type, _nbGameTypes-1);
00744 QString str = "scores";
00745 QString lab = manager.gameTypeLabel(_gameType, Manager::Standard);
00746 if ( !lab.isEmpty() ) {
00747 _playerInfos->setSubGroup(lab);
00748 str += "_" + lab;
00749 }
00750 _scoreInfos->setGroup(str);
00751 }
00752
00753 void ManagerPrivate::checkFirst()
00754 {
00755 if (_first) setGameType(0);
00756 }
00757
00758 int ManagerPrivate::submitScore(const Score &ascore,
00759 QWidget *widget, bool askIfAnonymous)
00760 {
00761 checkFirst();
00762
00763 Score score = ascore;
00764 score.setData("id", _playerInfos->id() + 1);
00765 score.setData("date", QDateTime::currentDateTime());
00766
00767
00768 const char *dontAskAgainName = "highscore_ask_name_dialog";
00769 QString newName;
00770 KMessageBox::ButtonCode dummy;
00771 if ( score.type()==Won && askIfAnonymous && _playerInfos->isAnonymous()
00772 && KMessageBox::shouldBeShownYesNo(dontAskAgainName, dummy) ) {
00773 AskNameDialog d(widget);
00774 if ( d.exec()==QDialog::Accepted ) newName = d.name();
00775 if ( d.dontAskAgain() )
00776 KMessageBox::saveDontShowAgainYesNo(dontAskAgainName,
00777 KMessageBox::No);
00778 }
00779
00780 int rank = -1;
00781 if ( _hsConfig->lockForWriting(widget) ) {
00782
00783 if ( !newName.isEmpty() && !_playerInfos->isNameUsed(newName) )
00784 _playerInfos->modifyName(newName);
00785
00786
00787 _playerInfos->submitScore(score);
00788 if ( score.type()==Won ) rank = submitLocal(score);
00789 _hsConfig->writeAndUnlock();
00790 }
00791
00792 if ( _playerInfos->isWWEnabled() )
00793 submitWorldWide(score, widget);
00794
00795 return rank;
00796 }
00797
00798 int ManagerPrivate::submitLocal(const Score &score)
00799 {
00800 int r = rank(score);
00801 if ( r!=-1 ) {
00802 uint nb = _scoreInfos->nbEntries();
00803 if ( nb<_scoreInfos->maxNbEntries() ) nb++;
00804 _scoreInfos->write(r, score, nb);
00805 }
00806 return r;
00807 }
00808
00809 bool ManagerPrivate::submitWorldWide(const Score &score,
00810 QWidget *widget) const
00811 {
00812 if ( score.type()==Lost && !trackLostGames ) return true;
00813
00814 KURL url = queryURL(Submit);
00815 manager.additionalQueryItems(url, score);
00816 int s = (score.type()==Won ? score.score() : (int)score.type());
00817 QString str = QString::number(s);
00818 Manager::addToQueryURL(url, "score", str);
00819 KMD5 context(QString(_playerInfos->registeredName() + str).latin1());
00820 Manager::addToQueryURL(url, "check", context.hexDigest());
00821
00822 return doQuery(url, widget);
00823 }
00824
00825 void ManagerPrivate::exportHighscores(QTextStream &s)
00826 {
00827 uint tmp = _gameType;
00828
00829 for (uint i=0; i<_nbGameTypes; i++) {
00830 setGameType(i);
00831 if ( _nbGameTypes>1 ) {
00832 if ( i!=0 ) s << endl;
00833 s << "--------------------------------" << endl;
00834 s << "Game type: "
00835 << manager.gameTypeLabel(_gameType, Manager::I18N)
00836 << endl;
00837 s << endl;
00838 }
00839 s << "Players list:" << endl;
00840 _playerInfos->exportToText(s);
00841 s << endl;
00842 s << "Highscores list:" << endl;
00843 _scoreInfos->exportToText(s);
00844 }
00845
00846 setGameType(tmp);
00847 }
00848
00849 }