libkdegames Library API Documentation

kexthighscore_internal.cpp

00001 /* 00002 This file is part of the KDE games library 00003 Copyright (C) 2001-02 Nicolas Hadacek (hadacek@kde.org) 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 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("") // no null groups 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 // standard items 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 // statistics items 00275 addItem("nb black marks", new Item((uint)0), true, true); // legacy 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) { // player already exists in local config file 00309 // copy player data 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 // update counts 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 // update mean 00397 if ( !lost ) { 00398 uint nbWonGames = nbGames - item("nb lost games")->read(_id).toUInt() 00399 - item("nb black marks")->read(_id).toUInt(); // legacy 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 // update best score 00407 Score best = score; //copy optionnal fields that are not taken into account 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 // update trends 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 // update histogram 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; // own name... 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 // save old key/nickname 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 // clear current key/nickname 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 // strings that needs to be translated (coming from the highscores server) 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); // remove cache ! 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); // no GUI when locking 00688 if (ok) { 00689 // check again name in case the config file has been changed... 00690 // if it has, it is unfortunate because the WWW name is already 00691 // committed but should be very rare and not really problematic 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 // read old highscores 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 // commit them 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 // convert legacy highscores 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 // convert local to global highscores 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 // ask new name if anonymous and winner 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) ) { // no GUI when locking 00782 // check again new name in case the config file has been changed... 00783 if ( !newName.isEmpty() && !_playerInfos->isNameUsed(newName) ) 00784 _playerInfos->modifyName(newName); 00785 00786 // commit locally 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 } // namespace
KDE Logo
This file is part of the documentation for libkdegames Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Sep 21 12:08:02 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003