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